blob: 48253791b8ae4fa64b83f355d4c9d231811d4140 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
jge62037862016-12-09 10:44:33 +08002 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ipa.c
30 *
31 * WLAN HDD and ipa interface implementation
32 * Originally written by Qualcomm Atheros, Inc
33 */
34
35#ifdef IPA_OFFLOAD
36
37/* Include Files */
Mohit Khannafa99aea2016-05-12 21:43:13 -070038#include <linux/ipa.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039#include <wlan_hdd_includes.h>
40#include <wlan_hdd_ipa.h>
41
42#include <linux/etherdevice.h>
43#include <linux/atomic.h>
44#include <linux/netdevice.h>
45#include <linux/skbuff.h>
46#include <linux/list.h>
47#include <linux/debugfs.h>
48#include <linux/inetdevice.h>
49#include <linux/ip.h>
50#include <wlan_hdd_softap_tx_rx.h>
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +053051#include <ol_txrx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070052#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053
54#include "cds_sched.h"
55
56#include "wma.h"
57#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080058#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
Dhanashri Atreb08959a2016-03-01 17:28:03 -080060#include "cdp_txrx_ipa.h"
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -080061#include <cdp_txrx_handle.h>
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -080062#include "wlan_policy_mgr_api.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
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -070094enum hdd_ipa_uc_op_code {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080095 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,
Yun Park637d6482016-10-05 10:51:33 -0700100#ifdef FEATURE_METERING
101 HDD_IPA_UC_OPCODE_SHARING_STATS = 5,
102 HDD_IPA_UC_OPCODE_QUOTA_RSP = 6,
103 HDD_IPA_UC_OPCODE_QUOTA_IND = 7,
104#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800105 HDD_IPA_UC_OPCODE_UC_READY = 8,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800106 /* keep this last */
107 HDD_IPA_UC_OPCODE_MAX
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700108};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800109
110/**
111 * enum - Reason codes for stat query
112 *
113 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
114 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
115 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800116 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800117 */
118enum {
119 HDD_IPA_UC_STAT_REASON_NONE,
120 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -0800121 HDD_IPA_UC_STAT_REASON_BW_CAL,
122 HDD_IPA_UC_STAT_REASON_DUMP_INFO
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800123};
124
125/**
126 * enum hdd_ipa_rm_state - IPA resource manager state
127 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
128 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
129 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
130 */
131enum hdd_ipa_rm_state {
132 HDD_IPA_RM_RELEASED,
133 HDD_IPA_RM_GRANT_PENDING,
134 HDD_IPA_RM_GRANTED,
135};
136
137struct llc_snap_hdr {
138 uint8_t dsap;
139 uint8_t ssap;
140 uint8_t resv[4];
141 __be16 eth_type;
142} __packed;
143
Leo Chang3bc8fed2015-11-13 10:59:47 -0800144/**
145 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
146 * @eth: ether II header
147 * @llc_snap: LLC snap header
148 *
149 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800150struct hdd_ipa_tx_hdr {
151 struct ethhdr eth;
152 struct llc_snap_hdr llc_snap;
153} __packed;
154
Leo Chang3bc8fed2015-11-13 10:59:47 -0800155/**
156 * struct frag_header - fragment header type registered to IPA hardware
157 * @length: fragment length
158 * @reserved1: Reserved not used
159 * @reserved2: Reserved not used
160 *
161 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800162struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800163 uint16_t length;
164 uint32_t reserved1;
165 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800166} __packed;
167
Leo Chang3bc8fed2015-11-13 10:59:47 -0800168/**
169 * struct ipa_header - ipa header type registered to IPA hardware
170 * @vdev_id: vdev id
171 * @reserved: Reserved not used
172 *
173 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174struct ipa_header {
175 uint32_t
176 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
177 reserved:24;
178} __packed;
179
Leo Chang3bc8fed2015-11-13 10:59:47 -0800180/**
181 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
182 * @frag_hd: fragment header
183 * @ipa_hd: ipa header
184 * @eth: ether II header
185 *
186 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800187struct hdd_ipa_uc_tx_hdr {
188 struct frag_header frag_hd;
189 struct ipa_header ipa_hd;
190 struct ethhdr eth;
191} __packed;
192
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800193/**
194 * struct hdd_ipa_cld_hdr - IPA CLD Header
195 * @reserved: reserved fields
196 * @iface_id: interface ID
197 * @sta_id: Station ID
198 *
199 * Packed 32-bit structure
200 * +----------+----------+--------------+--------+
201 * | Reserved | QCMAP ID | interface id | STA ID |
202 * +----------+----------+--------------+--------+
203 */
204struct hdd_ipa_cld_hdr {
205 uint8_t reserved[2];
206 uint8_t iface_id;
207 uint8_t sta_id;
208} __packed;
209
210struct hdd_ipa_rx_hdr {
211 struct hdd_ipa_cld_hdr cld_hdr;
212 struct ethhdr eth;
213} __packed;
214
215struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700216 bool exception;
217 hdd_adapter_t *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800218 struct hdd_ipa_iface_context *iface_context;
219 struct ipa_rx_data *ipa_tx_desc;
220};
221
222struct hdd_ipa_uc_rx_hdr {
223 struct ethhdr eth;
224} __packed;
225
226struct hdd_ipa_sys_pipe {
227 uint32_t conn_hdl;
228 uint8_t conn_hdl_valid;
229 struct ipa_sys_connect_params ipa_sys_params;
230};
231
232struct hdd_ipa_iface_stats {
233 uint64_t num_tx;
234 uint64_t num_tx_drop;
235 uint64_t num_tx_err;
236 uint64_t num_tx_cac_drop;
237 uint64_t num_rx_prefilter;
238 uint64_t num_rx_ipa_excep;
239 uint64_t num_rx_recv;
240 uint64_t num_rx_recv_mul;
241 uint64_t num_rx_send_desc_err;
242 uint64_t max_rx_mul;
243};
244
245struct hdd_ipa_priv;
246
247struct hdd_ipa_iface_context {
248 struct hdd_ipa_priv *hdd_ipa;
249 hdd_adapter_t *adapter;
250 void *tl_context;
251
252 enum ipa_client_type cons_client;
253 enum ipa_client_type prod_client;
254
255 uint8_t iface_id; /* This iface ID */
256 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530257 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800258 uint32_t ifa_address;
259 struct hdd_ipa_iface_stats stats;
260};
261
262struct hdd_ipa_stats {
263 uint32_t event[IPA_WLAN_EVENT_MAX];
264 uint64_t num_send_msg;
265 uint64_t num_free_msg;
266
267 uint64_t num_rm_grant;
268 uint64_t num_rm_release;
269 uint64_t num_rm_grant_imm;
270 uint64_t num_cons_perf_req;
271 uint64_t num_prod_perf_req;
272
273 uint64_t num_rx_drop;
274 uint64_t num_rx_ipa_tx_dp;
275 uint64_t num_rx_ipa_splice;
276 uint64_t num_rx_ipa_loop;
277 uint64_t num_rx_ipa_tx_dp_err;
278 uint64_t num_rx_ipa_write_done;
279 uint64_t num_max_ipa_tx_mul;
280 uint64_t num_rx_ipa_hw_maxed_out;
281 uint64_t max_pend_q_cnt;
282
283 uint64_t num_tx_comp_cnt;
284 uint64_t num_tx_queued;
285 uint64_t num_tx_dequeued;
286 uint64_t num_max_pm_queue;
287
288 uint64_t num_freeq_empty;
289 uint64_t num_pri_freeq_empty;
290 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800291 uint64_t num_tx_fwd_ok;
292 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800293};
294
295struct ipa_uc_stas_map {
296 bool is_reserved;
297 uint8_t sta_id;
298};
299struct op_msg_type {
300 uint8_t msg_t;
301 uint8_t rsvd;
302 uint16_t op_code;
303 uint16_t len;
304 uint16_t rsvd_snd;
305};
306
307struct ipa_uc_fw_stats {
308 uint32_t tx_comp_ring_base;
309 uint32_t tx_comp_ring_size;
310 uint32_t tx_comp_ring_dbell_addr;
311 uint32_t tx_comp_ring_dbell_ind_val;
312 uint32_t tx_comp_ring_dbell_cached_val;
313 uint32_t tx_pkts_enqueued;
314 uint32_t tx_pkts_completed;
315 uint32_t tx_is_suspend;
316 uint32_t tx_reserved;
317 uint32_t rx_ind_ring_base;
318 uint32_t rx_ind_ring_size;
319 uint32_t rx_ind_ring_dbell_addr;
320 uint32_t rx_ind_ring_dbell_ind_val;
321 uint32_t rx_ind_ring_dbell_ind_cached_val;
322 uint32_t rx_ind_ring_rdidx_addr;
323 uint32_t rx_ind_ring_rd_idx_cached_val;
324 uint32_t rx_refill_idx;
325 uint32_t rx_num_pkts_indicated;
326 uint32_t rx_buf_refilled;
327 uint32_t rx_num_ind_drop_no_space;
328 uint32_t rx_num_ind_drop_no_buf;
329 uint32_t rx_is_suspend;
330 uint32_t rx_reserved;
331};
332
333struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530334 qdf_list_node_t node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800335 hdd_adapter_t *adapter;
336 enum ipa_wlan_event type;
337 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530338 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800339};
340
341/**
342 * struct uc_rm_work_struct
343 * @work: uC RM work
344 * @event: IPA RM event
345 */
346struct uc_rm_work_struct {
347 struct work_struct work;
348 enum ipa_rm_event event;
349};
350
351/**
352 * struct uc_op_work_struct
353 * @work: uC OP work
354 * @msg: OP message
355 */
356struct uc_op_work_struct {
357 struct work_struct work;
358 struct op_msg_type *msg;
359};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800360
361/**
362 * struct uc_rt_debug_info
363 * @time: system time
364 * @ipa_excep_count: IPA exception packet count
365 * @rx_drop_count: IPA Rx drop packet count
366 * @net_sent_count: IPA Rx packet sent to network stack count
367 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800368 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800369 * @tx_fwd_count: IPA Tx forward packet count
370 * @rx_destructor_call: IPA Rx packet destructor count
371 */
372struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530373 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800374 uint64_t ipa_excep_count;
375 uint64_t rx_drop_count;
376 uint64_t net_sent_count;
377 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800378 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800379 uint64_t tx_fwd_count;
380 uint64_t rx_destructor_call;
381};
382
Yun Park637d6482016-10-05 10:51:33 -0700383#ifdef FEATURE_METERING
384struct ipa_uc_sharing_stats {
385 uint64_t ipv4_rx_packets;
386 uint64_t ipv4_rx_bytes;
387 uint64_t ipv6_rx_packets;
388 uint64_t ipv6_rx_bytes;
389 uint64_t ipv4_tx_packets;
390 uint64_t ipv4_tx_bytes;
391 uint64_t ipv6_tx_packets;
392 uint64_t ipv6_tx_bytes;
393};
394
395struct ipa_uc_quota_rsp {
396 uint8_t success;
397 uint8_t reserved[3];
398 uint32_t quota_lo; /* quota limit low bytes */
399 uint32_t quota_hi; /* quota limit high bytes */
400};
401
402struct ipa_uc_quota_ind {
403 uint64_t quota_bytes; /* quota limit in bytes */
404};
405#endif
406
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800407struct hdd_ipa_priv {
408 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
409 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
410 uint8_t num_iface;
411 enum hdd_ipa_rm_state rm_state;
412 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530413 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800414 * APIs as it is taken care gracefully. Without this, kernel would throw
415 * an warning if spin_lock_bh is used while IRQ is disabled
416 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530417 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800418 struct uc_rm_work_struct uc_rm_work;
419 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530420 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800421 struct delayed_work wake_lock_work;
422 bool wake_lock_released;
423
424 enum ipa_client_type prod_client;
425
426 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530427 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800428 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530429 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800430 bool suspended;
431
432 uint32_t pending_hw_desc_cnt;
433 uint32_t hw_desc_cnt;
434 spinlock_t q_lock;
435 uint32_t freeq_cnt;
436 struct list_head free_desc_head;
437
438 uint32_t pend_q_cnt;
439 struct list_head pend_desc_head;
440
441 hdd_context_t *hdd_ctx;
442
443 struct dentry *debugfs_dir;
444 struct hdd_ipa_stats stats;
445
446 struct notifier_block ipv4_notifier;
447 uint32_t curr_prod_bw;
448 uint32_t curr_cons_bw;
449
450 uint8_t activated_fw_pipe;
451 uint8_t sap_num_connected_sta;
452 uint8_t sta_connected;
453 uint32_t tx_pipe_handle;
454 uint32_t rx_pipe_handle;
455 bool resource_loading;
456 bool resource_unloading;
457 bool pending_cons_req;
458 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530459 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530460 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700461 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800462 uint32_t ipa_tx_packets_diff;
463 uint32_t ipa_rx_packets_diff;
464 uint32_t ipa_p_tx_packets;
465 uint32_t ipa_p_rx_packets;
466 uint32_t stat_req_reason;
467 uint64_t ipa_tx_forward;
468 uint64_t ipa_rx_discard;
469 uint64_t ipa_rx_net_send_count;
470 uint64_t ipa_rx_internel_drop_count;
471 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530472 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800473 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
474 unsigned int rt_buf_fill_index;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800475 struct ipa_wdi_in_params cons_pipe_in;
476 struct ipa_wdi_in_params prod_pipe_in;
477 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800478 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530479 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530480 qdf_mutex_t rt_debug_lock;
481 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800482 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800483 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530484 qdf_dma_addr_t tx_comp_doorbell_paddr;
485 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800486 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
487 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Yun Park637d6482016-10-05 10:51:33 -0700488#ifdef FEATURE_METERING
489 struct ipa_uc_sharing_stats ipa_sharing_stats;
490 struct ipa_uc_quota_rsp ipa_quota_rsp;
491 struct ipa_uc_quota_ind ipa_quota_ind;
492 struct completion ipa_uc_sharing_stats_comp;
493 struct completion ipa_uc_set_quota_comp;
494#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800495};
496
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800497/**
Houston Hoffman23e76f92016-02-26 12:19:11 -0800498 * FIXME: The following conversion routines are just stubs.
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800499 * They will be implemented fully by another update.
500 * The stubs will let the compile go ahead, and functionality
501 * is broken.
502 * This should be OK and IPA is not enabled yet
503 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700504static void *wlan_hdd_stub_priv_to_addr(uint32_t priv)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800505{
506 void *vaddr;
507 uint32_t ipa_priv = priv;
508
509 vaddr = &ipa_priv; /* just to use the var */
510 vaddr = NULL;
511 return vaddr;
512}
513
Jeff Johnsond7720632016-10-05 16:04:32 -0700514static uint32_t wlan_hdd_stub_addr_to_priv(void *ptr)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800515{
516 uint32_t ipa_priv = 0;
517
518 BUG_ON(ptr == NULL);
519 return ipa_priv;
520}
Leo Changcc923e22016-06-16 15:29:03 -0700521
522#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
523#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800524#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
525#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
526#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
527#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
528#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
529#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700530#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
531 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800532
533#define HDD_IPA_GET_IFACE_ID(_data) \
534 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
535
536#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530537 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800538 "%s:%d: "fmt, __func__, __LINE__, ## args)
539
Govind Singhb6a89772016-08-12 11:23:35 +0530540#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
541 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
542 "%s:%d: "fmt, __func__, __LINE__, ## args)
543
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800544#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
545 do { \
Yun Parkec845302016-12-15 09:22:57 -0800546 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \
547 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800548 } while (0)
549
550#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
551 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
552
553#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
554 do { \
555 hdd_ipa->ipa_rx_internel_drop_count++; \
556 } while (0)
557#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
558 do { \
559 hdd_ipa->ipa_rx_net_send_count++; \
560 } while (0)
561#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
562
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700563#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800564#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
565do { \
566 pipe_in.u.ul.rdy_ring_rp_va = \
567 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
568 pipe_in.u.ul.rdy_comp_ring_base_pa = \
569 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
570 pipe_in.u.ul.rdy_comp_ring_size = \
571 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
572 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
573 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
574 pipe_in.u.ul.rdy_comp_ring_wp_va = \
575 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800576} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700577
578#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800579#else
580/* Do nothing */
581#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
Leo Chang63d73612016-10-18 18:09:43 -0700582#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700583#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800584
Yun Parkb187d542016-11-14 18:10:04 -0800585#define HDD_IPA_DBG_DUMP_RX_LEN 32
586#define HDD_IPA_DBG_DUMP_TX_LEN 48
587
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800588static struct hdd_ipa_adapter_2_client {
589 enum ipa_client_type cons_client;
590 enum ipa_client_type prod_client;
591} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
592 {
593 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
594 }, {
595 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
596 }, {
597 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
598 },
599};
600
601/* For Tx pipes, use Ethernet-II Header format */
602struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
603 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800604 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800605 0x00000000,
606 0x00000000
607 },
608 {
609 0x00000000
610 },
611 {
612 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
613 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
614 0x0008
615 }
616};
617
618/* For Tx pipes, use 802.3 Header format */
619static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
620 {
621 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
622 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
623 0x00 /* length can be zero */
624 },
625 {
626 /* LLC SNAP header 8 bytes */
627 0xaa, 0xaa,
628 {0x03, 0x00, 0x00, 0x00},
629 0x0008 /* type value(2 bytes) ,filled by wlan */
630 /* 0x0800 - IPV4, 0x86dd - IPV6 */
631 }
632};
633
Yun Park637d6482016-10-05 10:51:33 -0700634#ifdef FEATURE_METERING
635#define IPA_UC_SHARING_STATES_WAIT_TIME 500
636#define IPA_UC_SET_QUOTA_WAIT_TIME 500
637#endif
638
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800639static struct hdd_ipa_priv *ghdd_ipa;
640
641/* Local Function Prototypes */
642static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
643 unsigned long data);
644static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
645 unsigned long data);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800646static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800647
648static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700649static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800650
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800651#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
652 defined(IPA_CLIENT_IS_MHI_CONS))
653/**
654 * hdd_ipa_uc_get_db_paddr() - Get Doorbell physical address
655 * @db_paddr: Doorbell physical address should be given bu IPA
656 * @client: IPA client type
657 *
658 * Query doorbell physical address from IPA
659 * IPA will give physical address for TX COMP and RX READY
660 *
661 * Return: None
662 */
663static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
664 enum ipa_client_type client)
665{
666 struct ipa_wdi_db_params dbpa;
667
668 dbpa.client = client;
669 ipa_uc_wdi_get_dbpa(&dbpa);
670 *db_paddr = dbpa.uc_door_bell_pa;
Srinivas Girigowda97852372017-03-06 16:52:59 -0800671 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s PROD DB get dbpa 0x%x",
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800672 __func__, (unsigned int)dbpa.uc_door_bell_pa);
673}
674
675/**
676 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
677 * @priv_ctxt: hdd ipa local context
678 *
679 * Will be called by IPA context.
680 * It's atomic context, then should be scheduled to kworker thread
681 *
682 * Return: None
683 */
684static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
685{
686 struct hdd_ipa_priv *hdd_ipa;
687 struct op_msg_type *msg;
688 struct uc_op_work_struct *uc_op_work;
689
690 if (priv_ctxt == NULL) {
691 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
692 return;
693 }
694
695 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
696 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
697 if (!msg) {
698 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
699 return;
700 }
701
702 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
703
704 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
705
706 /* When the same uC OPCODE is already pended, just return */
707 if (uc_op_work->msg)
708 return;
709
710 uc_op_work->msg = msg;
711 schedule_work(&uc_op_work->work);
712}
713
714/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800715 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
716 * @ctrl: WDI control value
717 *
718 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
719 *
720 * Return: 0 on message send to ipa, -1 on failure
721 */
722static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
723{
724 struct ipa_msg_meta meta;
725 struct ipa_wlan_msg *ipa_msg;
726 int ret = 0;
727
728 /* WDI enable message to IPA */
729 meta.msg_len = sizeof(*ipa_msg);
730 ipa_msg = qdf_mem_malloc(meta.msg_len);
731 if (ipa_msg == NULL) {
732 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
733 "msg allocation failed");
734 return -ENOMEM;
735 }
736
737 if (ctrl == true)
738 meta.msg_type = WLAN_WDI_ENABLE;
739 else
740 meta.msg_type = WLAN_WDI_DISABLE;
741
Srinivas Girigowda97852372017-03-06 16:52:59 -0800742 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800743 "ipa_send_msg(Evt:%d)", meta.msg_type);
744 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
745 if (ret) {
746 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
747 "ipa_send_msg(Evt:%d)-fail=%d",
748 meta.msg_type, ret);
749 qdf_mem_free(ipa_msg);
750 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800751 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800752}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800753
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800754/**
755 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
756 * @hdd_ipa: HDD IPA local context
757 *
758 * Register IPA UC ready callback function to IPA kernel driver
759 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
760 * open WDI pipe after WLAN driver loading finished
761 *
762 * Return: 0 Success
763 * -EPERM Registration fail
764 */
765static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
766{
767 struct ipa_wdi_uc_ready_params uc_ready_param;
768 int ret = 0;
769
770 hdd_ipa->uc_loaded = false;
771 uc_ready_param.priv = (void *)hdd_ipa;
772 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
773 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
774 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
775 "UC Ready CB register fail");
776 return -EPERM;
777 }
778 if (true == uc_ready_param.is_uC_ready) {
779 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "UC Ready");
780 hdd_ipa->uc_loaded = true;
781 } else {
782 ret = hdd_ipa_uc_send_wdi_control_msg(false);
783 }
784
785 return ret;
786}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800787#else
788static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
789 enum ipa_client_type client)
790{
791 /* Do nothing */
792}
793
794static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
795{
796 hdd_ipa->uc_loaded = true;
797 return 0;
798}
799
800static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
801{
802 return 0;
803}
804#endif
805
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800806/**
807 * hdd_ipa_is_enabled() - Is IPA enabled?
808 * @hdd_ctx: Global HDD context
809 *
810 * Return: true if IPA is enabled, false otherwise
811 */
812bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
813{
814 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
815}
816
817/**
818 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
819 * @hdd_ctx: Global HDD context
820 *
821 * Return: true if IPA uC offload is enabled, false otherwise
822 */
823bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
824{
825 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
826}
827
828/**
829 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
830 * @hdd_ctx: Global HDD context
831 *
832 * Return: true if STA mode IPA uC offload is enabled, false otherwise
833 */
834static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
835{
836 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
837}
838
839/**
Guolei Bianca144d82016-11-10 11:07:42 +0800840 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
841 * @hdd_ipa: Global HDD IPA context
842 *
843 * Return: None
844 */
Guolei Bianca144d82016-11-10 11:07:42 +0800845static inline void hdd_ipa_uc_sta_reset_sta_connected(
846 struct hdd_ipa_priv *hdd_ipa)
847{
Yun Park637d6482016-10-05 10:51:33 -0700848 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800849 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700850 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800851}
Guolei Bianca144d82016-11-10 11:07:42 +0800852
853/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
855 * @hdd_ipa: Global HDD IPA context
856 *
857 * Return: true if pre-filter is enabled, otherwise false
858 */
859static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
860{
861 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
862 HDD_IPA_PRE_FILTER_ENABLE_MASK);
863}
864
865/**
866 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
867 * @hdd_ipa: Global HDD IPA context
868 *
869 * Return: true if IPv6 is enabled, otherwise false
870 */
871static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
872{
873 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
874}
875
876/**
877 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
878 * @hdd_ipa: Global HDD IPA context
879 *
880 * Return: true if resource manager is enabled, otherwise false
881 */
882static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
883{
884 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
885}
886
887/**
888 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
889 * @hdd_ipa: Global HDD IPA context
890 *
891 * Return: true if resource manager is enabled, otherwise false
892 */
893static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
894{
895 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
896}
897
898/**
899 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
900 * @hdd_ipa: Global HDD IPA context
901 *
902 * Return: true if clock scaling is enabled, otherwise false
903 */
904static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
905{
906 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
907 HDD_IPA_CLK_SCALING_ENABLE_MASK |
908 HDD_IPA_RM_ENABLE_MASK);
909}
910
911/**
912 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
913 * @ctext: pointer to hdd context.
914 *
915 * If rt debug enabled, periodically called, and fill debug buffer
916 *
917 * Return: none
918 */
919static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
920{
921 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
922 struct hdd_ipa_priv *hdd_ipa;
923 struct uc_rt_debug_info *dump_info = NULL;
924
925 if (wlan_hdd_validate_context(hdd_ctx))
926 return;
927
928 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800929 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800930 "%s: IPA UC is not enabled", __func__);
931 return;
932 }
933
934 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
935
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530936 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800937 dump_info = &hdd_ipa->rt_bug_buffer[
938 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
939
Deepthi Gowri6acee342016-10-28 15:00:38 +0530940 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
942 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
943 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800945 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
946 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800947 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
948 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530949 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800950
Anurag Chouhan210db072016-02-22 18:42:15 +0530951 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800952 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
953}
954
955/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700956 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800957 * @hdd_ctx: pointer to hdd context.
958 *
959 * If rt debug enabled, dump debug buffer contents based on requirement
960 *
961 * Return: none
962 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700963static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964{
965 struct hdd_ipa_priv *hdd_ipa;
966 unsigned int dump_count;
967 unsigned int dump_index;
968 struct uc_rt_debug_info *dump_info = NULL;
969
970 if (wlan_hdd_validate_context(hdd_ctx))
971 return;
972
973 hdd_ipa = hdd_ctx->hdd_ipa;
974 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800975 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800976 "%s: IPA UC is not enabled", __func__);
977 return;
978 }
979
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530980 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800981 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530982 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800983 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800984
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530985 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800986 for (dump_count = 0;
987 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
988 dump_count++) {
989 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
990 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
991 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530992 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530993 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994 dump_info->time, dump_info->ipa_excep_count,
995 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800996 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800997 dump_info->rx_destructor_call,
998 dump_info->rx_discard_count);
999 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301000 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301001 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001002 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
1003}
1004
1005/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001006 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
1007 * __hdd_ipa_uc_rt_debug_host_dump
1008 * @hdd_ctx: pointer to hdd context.
1009 *
1010 * If rt debug enabled, dump debug buffer contents based on requirement
1011 *
1012 * Return: none
1013 */
1014void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
1015{
1016 cds_ssr_protect(__func__);
1017 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1018 cds_ssr_unprotect(__func__);
1019}
1020
1021/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001022 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
1023 * @ctext: pointer to hdd context.
1024 *
1025 * periodically called by timer expire
1026 * will try to alloc dummy memory and detect out of memory condition
1027 * if out of memory detected, dump wlan-ipa stats
1028 *
1029 * Return: none
1030 */
1031static void hdd_ipa_uc_rt_debug_handler(void *ctext)
1032{
1033 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001034 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035 void *dummy_ptr = NULL;
1036
1037 if (wlan_hdd_validate_context(hdd_ctx))
1038 return;
1039
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001040 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1041
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001043 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044 return;
1045 }
1046
1047 /* Allocate dummy buffer periodically and free immediately. this will
1048 * proactively detect OOM and if allocation fails dump ipa stats
1049 */
1050 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
1051 GFP_KERNEL | GFP_ATOMIC);
1052 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001053 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1054 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -07001055 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
1056 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057 } else {
1058 kfree(dummy_ptr);
1059 }
1060
Anurag Chouhan210db072016-02-22 18:42:15 +05301061 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001062 HDD_IPA_UC_RT_DEBUG_PERIOD);
1063}
1064
1065/**
Yun Parkb187d542016-11-14 18:10:04 -08001066 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001067 * @skb: packet pinter
1068 *
1069 * when free data packet, will be invoked by wlan client and will increase
1070 * free counter
1071 *
1072 * Return: none
1073 */
Jeff Johnsond7720632016-10-05 16:04:32 -07001074static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001075{
1076 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301077 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001078 "%s: invalid hdd context", __func__);
1079 return;
1080 }
1081
1082 ghdd_ipa->ipa_rx_destructor_count++;
1083}
1084
1085/**
Yun Parkb187d542016-11-14 18:10:04 -08001086 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001087 * @hdd_ctx: hdd main context
1088 *
1089 * free all rt debugging resources
1090 *
1091 * Return: none
1092 */
1093static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
1094{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001095 struct hdd_ipa_priv *hdd_ipa;
1096
1097 if (wlan_hdd_validate_context(hdd_ctx))
1098 return;
1099
1100 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001101
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301102 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103
1104 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001105 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106 return;
1107 }
1108
Anurag Chouhan210db072016-02-22 18:42:15 +05301109 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001110 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1111 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1112 }
1113 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1114
1115 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301116 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1117 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301119 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001120}
1121
1122/**
Yun Parkb187d542016-11-14 18:10:04 -08001123 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001124 * @hdd_ctx: hdd main context
1125 *
1126 * alloc and initialize all rt debugging resources
1127 *
1128 * Return: none
1129 */
1130static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
1131{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001132 struct hdd_ipa_priv *hdd_ipa;
1133
1134 if (wlan_hdd_validate_context(hdd_ctx))
1135 return;
1136
1137 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001138
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301139 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301141 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142 sizeof(struct uc_rt_debug_info) *
1143 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1144 hdd_ipa->ipa_tx_forward = 0;
1145 hdd_ipa->ipa_rx_discard = 0;
1146 hdd_ipa->ipa_rx_net_send_count = 0;
1147 hdd_ipa->ipa_rx_internel_drop_count = 0;
1148 hdd_ipa->ipa_rx_destructor_count = 0;
1149
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001150 /* Reatime debug enable on feature enable */
1151 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001152 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001153 return;
1154 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001155
1156 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1157 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1158 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1159 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1160
Anurag Chouhan210db072016-02-22 18:42:15 +05301161 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001162 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301163 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001164 HDD_IPA_UC_RT_DEBUG_PERIOD);
1165
1166}
1167
1168/**
Yun Parkb187d542016-11-14 18:10:04 -08001169 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1170 * @hdd_ipa: HDD IPA struct
1171 *
1172 * Dump entries in struct hdd_ipa
1173 *
1174 * Return: none
1175 */
1176static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1177{
1178 int i;
1179
1180 /* HDD IPA */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001181 hdd_info("==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001182 "num_iface: %d\n"
1183 "rm_state: %d\n"
1184 "rm_lock: %p\n"
1185 "uc_rm_work: %p\n"
1186 "uc_op_work: %p\n"
1187 "wake_lock: %p\n"
1188 "wake_lock_work: %p\n"
1189 "wake_lock_released: %d\n"
1190 "prod_client: %d\n"
1191 "tx_ref_cnt: %d\n"
1192 "pm_queue_head----\n"
1193 "\thead: %p\n"
1194 "\ttail: %p\n"
1195 "\tqlen: %d\n"
1196 "pm_work: %p\n"
1197 "pm_lock: %p\n"
1198 "suspended: %d\n",
1199 hdd_ipa->num_iface,
1200 hdd_ipa->rm_state,
1201 &hdd_ipa->rm_lock,
1202 &hdd_ipa->uc_rm_work,
1203 &hdd_ipa->uc_op_work,
1204 &hdd_ipa->wake_lock,
1205 &hdd_ipa->wake_lock_work,
1206 hdd_ipa->wake_lock_released,
1207 hdd_ipa->prod_client,
1208 hdd_ipa->tx_ref_cnt.counter,
1209 hdd_ipa->pm_queue_head.head,
1210 hdd_ipa->pm_queue_head.tail,
1211 hdd_ipa->pm_queue_head.qlen,
1212 &hdd_ipa->pm_work,
1213 &hdd_ipa->pm_lock,
1214 hdd_ipa->suspended);
Srinivas Girigowda97852372017-03-06 16:52:59 -08001215 hdd_info("\npending_hw_desc_cnt: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001216 "hw_desc_cnt: %d\n"
1217 "q_lock: %p\n"
1218 "freeq_cnt: %d\n"
1219 "free_desc_head----\n"
1220 "\tnext: %p\n"
1221 "\tprev: %p\n"
1222 "pend_q_cnt: %d\n"
1223 "pend_desc_head----\n"
1224 "\tnext: %p\n"
1225 "\tprev: %p\n"
1226 "hdd_ctx: %p\n"
1227 "debugfs_dir: %p\n"
1228 "stats: %p\n"
1229 "ipv4_notifier: %p\n"
1230 "curr_prod_bw: %d\n"
1231 "curr_cons_bw: %d\n"
1232 "activated_fw_pipe: %d\n"
1233 "sap_num_connected_sta: %d\n"
1234 "sta_connected: %d\n",
1235 hdd_ipa->pending_hw_desc_cnt,
1236 hdd_ipa->hw_desc_cnt,
1237 &hdd_ipa->q_lock,
1238 hdd_ipa->freeq_cnt,
1239 hdd_ipa->free_desc_head.next,
1240 hdd_ipa->free_desc_head.prev,
1241 hdd_ipa->pend_q_cnt,
1242 hdd_ipa->pend_desc_head.next,
1243 hdd_ipa->pend_desc_head.prev,
1244 hdd_ipa->hdd_ctx,
1245 hdd_ipa->debugfs_dir,
1246 &hdd_ipa->stats,
1247 &hdd_ipa->ipv4_notifier,
1248 hdd_ipa->curr_prod_bw,
1249 hdd_ipa->curr_cons_bw,
1250 hdd_ipa->activated_fw_pipe,
1251 hdd_ipa->sap_num_connected_sta,
1252 (unsigned int)hdd_ipa->sta_connected
1253 );
Srinivas Girigowda97852372017-03-06 16:52:59 -08001254 hdd_info("\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001255 "rx_pipe_handle: 0x%x\n"
1256 "resource_loading: %d\n"
1257 "resource_unloading: %d\n"
1258 "pending_cons_req: %d\n"
1259 "pending_event----\n"
1260 "\tanchor.next: %p\n"
1261 "\tanchor.prev: %p\n"
1262 "\tcount: %d\n"
1263 "\tmax_size: %d\n"
1264 "event_lock: %p\n"
1265 "ipa_tx_packets_diff: %d\n"
1266 "ipa_rx_packets_diff: %d\n"
1267 "ipa_p_tx_packets: %d\n"
1268 "ipa_p_rx_packets: %d\n"
1269 "stat_req_reason: %d\n",
1270 hdd_ipa->tx_pipe_handle,
1271 hdd_ipa->rx_pipe_handle,
1272 hdd_ipa->resource_loading,
1273 hdd_ipa->resource_unloading,
1274 hdd_ipa->pending_cons_req,
1275 hdd_ipa->pending_event.anchor.next,
1276 hdd_ipa->pending_event.anchor.prev,
1277 hdd_ipa->pending_event.count,
1278 hdd_ipa->pending_event.max_size,
1279 &hdd_ipa->event_lock,
1280 hdd_ipa->ipa_tx_packets_diff,
1281 hdd_ipa->ipa_rx_packets_diff,
1282 hdd_ipa->ipa_p_tx_packets,
1283 hdd_ipa->ipa_p_rx_packets,
1284 hdd_ipa->stat_req_reason);
1285
Srinivas Girigowda97852372017-03-06 16:52:59 -08001286 hdd_info("assoc_stas_map([id]is_reserved/sta_id): ");
Yun Parkb187d542016-11-14 18:10:04 -08001287 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001288 hdd_info(" [%d]%d/%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001289 hdd_ipa->assoc_stas_map[i].is_reserved,
1290 hdd_ipa->assoc_stas_map[i].sta_id);
1291 }
1292}
1293
1294/**
1295 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1296 * @hdd_ipa: HDD IPA struct
1297 *
1298 * Dump entire struct hdd_ipa_sys_pipe
1299 *
1300 * Return: none
1301 */
1302static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1303{
1304 int i;
1305
1306 /* IPA SYS Pipes */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001307 hdd_info("==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001308
1309 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1310 struct hdd_ipa_sys_pipe *sys_pipe;
1311 struct ipa_sys_connect_params *ipa_sys_params;
1312
1313 sys_pipe = &hdd_ipa->sys_pipe[i];
1314 ipa_sys_params = &sys_pipe->ipa_sys_params;
1315
Srinivas Girigowda97852372017-03-06 16:52:59 -08001316 hdd_info("sys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001317 "\tconn_hdl: 0x%x\n"
1318 "\tconn_hdl_valid: %d\n"
1319 "\tnat_en: %d\n"
1320 "\thdr_len %d\n"
1321 "\thdr_additional_const_len: %d\n"
1322 "\thdr_ofst_pkt_size_valid: %d\n"
1323 "\thdr_ofst_pkt_size: %d\n"
1324 "\thdr_little_endian: %d\n"
1325 "\tmode: %d\n"
1326 "\tclient: %d\n"
1327 "\tdesc_fifo_sz: %d\n"
1328 "\tpriv: %p\n"
1329 "\tnotify: %p\n"
1330 "\tskip_ep_cfg: %d\n"
1331 "\tkeep_ipa_awake: %d\n",
1332 i,
1333 sys_pipe->conn_hdl,
1334 sys_pipe->conn_hdl_valid,
1335 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1336 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1337 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1338 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1339 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1340 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1341 ipa_sys_params->ipa_ep_cfg.mode.mode,
1342 ipa_sys_params->client,
1343 ipa_sys_params->desc_fifo_sz,
1344 ipa_sys_params->priv,
1345 ipa_sys_params->notify,
1346 ipa_sys_params->skip_ep_cfg,
1347 ipa_sys_params->keep_ipa_awake);
1348 }
1349}
1350
1351/**
1352 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1353 * @hdd_ipa: HDD IPA struct
1354 *
1355 * Dump entire struct hdd_ipa_iface_context
1356 *
1357 * Return: none
1358 */
1359static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1360{
1361 int i;
1362
1363 /* IPA Interface Contexts */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001364 hdd_info("==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001365
1366 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1367 struct hdd_ipa_iface_context *iface_context;
1368
1369 iface_context = &hdd_ipa->iface_context[i];
1370
Srinivas Girigowda97852372017-03-06 16:52:59 -08001371 hdd_info("iface_context[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001372 "\thdd_ipa: %p\n"
1373 "\tadapter: %p\n"
1374 "\ttl_context: %p\n"
1375 "\tcons_client: %d\n"
1376 "\tprod_client: %d\n"
1377 "\tiface_id: %d\n"
1378 "\tsta_id: %d\n"
1379 "\tinterface_lock: %p\n"
1380 "\tifa_address: 0x%x\n",
1381 i,
1382 iface_context->hdd_ipa,
1383 iface_context->adapter,
1384 iface_context->tl_context,
1385 iface_context->cons_client,
1386 iface_context->prod_client,
1387 iface_context->iface_id,
1388 iface_context->sta_id,
1389 &iface_context->interface_lock,
1390 iface_context->ifa_address);
1391 }
1392}
1393
1394/**
1395 * hdd_ipa_dump_info() - dump HDD IPA struct
1396 * @pHddCtx: hdd main context
1397 *
1398 * Dump entire struct hdd_ipa
1399 *
1400 * Return: none
1401 */
1402void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1403{
1404 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1405
1406 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1407 hdd_ipa_dump_sys_pipe(hdd_ipa);
1408 hdd_ipa_dump_iface_context(hdd_ipa);
1409}
1410
1411/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001412 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1413 * enabled
1414 *
1415 * This routine is called to set TX flow info if IPA is enabled
1416 *
1417 * Return: None
1418 */
1419void hdd_ipa_set_tx_flow_info(void)
1420{
1421 hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL;
1422 QDF_STATUS status;
1423 hdd_adapter_t *adapter;
1424 hdd_station_ctx_t *pHddStaCtx;
1425 hdd_ap_ctx_t *hdd_ap_ctx;
1426 hdd_hostapd_state_t *hostapd_state;
1427 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1428 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1429 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1430 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1431 const char *p2pMode = "DEV";
1432 hdd_context_t *hdd_ctx;
1433 cds_context_type *cds_ctx;
1434#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1435 uint8_t targetChannel = 0;
1436 uint8_t preAdapterChannel = 0;
1437 uint8_t channel24;
1438 uint8_t channel5;
1439 hdd_adapter_t *preAdapterContext = NULL;
1440 hdd_adapter_t *adapter2_4 = NULL;
1441 hdd_adapter_t *adapter5 = NULL;
1442 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1443#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1444 struct wlan_objmgr_psoc *psoc;
1445
1446 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1447 if (!hdd_ctx) {
1448 cds_err("HDD context is NULL");
1449 return;
1450 }
1451
1452 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1453 if (!cds_ctx) {
1454 cds_err("Invalid CDS Context");
1455 return;
1456 }
1457
1458 psoc = hdd_ctx->hdd_psoc;
1459 status = hdd_get_front_adapter(hdd_ctx, &adapterNode);
1460 while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) {
1461 adapter = adapterNode->pAdapter;
1462 switch (adapter->device_mode) {
1463 case QDF_STA_MODE:
1464 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1465 if (eConnectionState_Associated ==
1466 pHddStaCtx->conn_info.connState) {
1467 staChannel =
1468 pHddStaCtx->conn_info.operationChannel;
1469 qdf_copy_macaddr(&staBssid,
1470 &pHddStaCtx->conn_info.bssId);
1471#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1472 targetChannel = staChannel;
1473#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1474 }
1475 break;
1476 case QDF_P2P_CLIENT_MODE:
1477 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1478 if (eConnectionState_Associated ==
1479 pHddStaCtx->conn_info.connState) {
1480 p2pChannel =
1481 pHddStaCtx->conn_info.operationChannel;
1482 qdf_copy_macaddr(&p2pBssid,
1483 &pHddStaCtx->conn_info.bssId);
1484 p2pMode = "CLI";
1485#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1486 targetChannel = p2pChannel;
1487#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1488 }
1489 break;
1490 case QDF_P2P_GO_MODE:
1491 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1492 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1493 if (hostapd_state->bssState == BSS_START
1494 && hostapd_state->qdf_status ==
1495 QDF_STATUS_SUCCESS) {
1496 p2pChannel = hdd_ap_ctx->operatingChannel;
1497 qdf_copy_macaddr(&p2pBssid,
1498 &adapter->macAddressCurrent);
1499#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1500 targetChannel = p2pChannel;
1501#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1502 }
1503 p2pMode = "GO";
1504 break;
1505 case QDF_SAP_MODE:
1506 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1507 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1508 if (hostapd_state->bssState == BSS_START
1509 && hostapd_state->qdf_status ==
1510 QDF_STATUS_SUCCESS) {
1511 apChannel = hdd_ap_ctx->operatingChannel;
1512 qdf_copy_macaddr(&apBssid,
1513 &adapter->macAddressCurrent);
1514#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1515 targetChannel = apChannel;
1516#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1517 }
1518 break;
1519 case QDF_IBSS_MODE:
1520 default:
1521 break;
1522 }
1523#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1524 if (targetChannel) {
1525 /*
1526 * This is first adapter detected as active
1527 * set as default for none concurrency case
1528 */
1529 if (!preAdapterChannel) {
1530 /* If IPA UC data path is enabled,
1531 * target should reserve extra tx descriptors
1532 * for IPA data path.
1533 * Then host data path should allow less TX
1534 * packet pumping in case IPA
1535 * data path enabled
1536 */
1537 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1538 (QDF_SAP_MODE == adapter->device_mode)) {
1539 adapter->tx_flow_low_watermark =
1540 hdd_ctx->config->TxFlowLowWaterMark +
1541 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1542 } else {
1543 adapter->tx_flow_low_watermark =
1544 hdd_ctx->config->
1545 TxFlowLowWaterMark;
1546 }
1547 adapter->tx_flow_high_watermark_offset =
1548 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1549 cdp_fc_ll_set_tx_pause_q_depth(soc,
1550 adapter->sessionId,
1551 hdd_ctx->config->TxFlowMaxQueueDepth);
1552 cds_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
1553 adapter->device_mode,
1554 targetChannel,
1555 adapter->tx_flow_low_watermark,
1556 adapter->tx_flow_low_watermark +
1557 adapter->tx_flow_high_watermark_offset,
1558 hdd_ctx->config->TxFlowMaxQueueDepth);
1559 preAdapterChannel = targetChannel;
1560 preAdapterContext = adapter;
1561 } else {
1562 /*
1563 * SCC, disable TX flow control for both
1564 * SCC each adapter cannot reserve dedicated
1565 * channel resource, as a result, if any adapter
1566 * blocked OS Q by flow control,
1567 * blocked adapter will lost chance to recover
1568 */
1569 if (preAdapterChannel == targetChannel) {
1570 /* Current adapter */
1571 adapter->tx_flow_low_watermark = 0;
1572 adapter->
1573 tx_flow_high_watermark_offset = 0;
1574 cdp_fc_ll_set_tx_pause_q_depth(soc,
1575 adapter->sessionId,
1576 hdd_ctx->config->
1577 TxHbwFlowMaxQueueDepth);
1578 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1579 hdd_device_mode_to_string(
1580 adapter->device_mode),
1581 adapter->device_mode,
1582 targetChannel,
1583 adapter->tx_flow_low_watermark,
1584 adapter->tx_flow_low_watermark +
1585 adapter->
1586 tx_flow_high_watermark_offset,
1587 hdd_ctx->config->
1588 TxHbwFlowMaxQueueDepth);
1589
1590 if (!preAdapterContext) {
1591 cds_err("SCC: Previous adapter context NULL");
1592 continue;
1593 }
1594
1595 /* Previous adapter */
1596 preAdapterContext->
1597 tx_flow_low_watermark = 0;
1598 preAdapterContext->
1599 tx_flow_high_watermark_offset = 0;
1600 cdp_fc_ll_set_tx_pause_q_depth(soc,
1601 preAdapterContext->sessionId,
1602 hdd_ctx->config->
1603 TxHbwFlowMaxQueueDepth);
1604 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1605 hdd_device_mode_to_string(
1606 preAdapterContext->device_mode
1607 ),
1608 preAdapterContext->device_mode,
1609 targetChannel,
1610 preAdapterContext->
1611 tx_flow_low_watermark,
1612 preAdapterContext->
1613 tx_flow_low_watermark +
1614 preAdapterContext->
1615 tx_flow_high_watermark_offset,
1616 hdd_ctx->config->
1617 TxHbwFlowMaxQueueDepth);
1618 }
1619 /*
1620 * MCC, each adapter will have dedicated
1621 * resource
1622 */
1623 else {
1624 /* current channel is 2.4 */
1625 if (targetChannel <=
1626 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1627 channel24 = targetChannel;
1628 channel5 = preAdapterChannel;
1629 adapter2_4 = adapter;
1630 adapter5 = preAdapterContext;
1631 } else {
1632 /* Current channel is 5 */
1633 channel24 = preAdapterChannel;
1634 channel5 = targetChannel;
1635 adapter2_4 = preAdapterContext;
1636 adapter5 = adapter;
1637 }
1638
1639 if (!adapter5) {
1640 cds_err("MCC: 5GHz adapter context NULL");
1641 continue;
1642 }
1643 adapter5->tx_flow_low_watermark =
1644 hdd_ctx->config->
1645 TxHbwFlowLowWaterMark;
1646 adapter5->
1647 tx_flow_high_watermark_offset =
1648 hdd_ctx->config->
1649 TxHbwFlowHighWaterMarkOffset;
1650 cdp_fc_ll_set_tx_pause_q_depth(soc,
1651 adapter5->sessionId,
1652 hdd_ctx->config->
1653 TxHbwFlowMaxQueueDepth);
1654 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1655 hdd_device_mode_to_string(
1656 adapter5->device_mode),
1657 adapter5->device_mode,
1658 channel5,
1659 adapter5->tx_flow_low_watermark,
1660 adapter5->
1661 tx_flow_low_watermark +
1662 adapter5->
1663 tx_flow_high_watermark_offset,
1664 hdd_ctx->config->
1665 TxHbwFlowMaxQueueDepth);
1666
1667 if (!adapter2_4) {
1668 cds_err("MCC: 2.4GHz adapter context NULL");
1669 continue;
1670 }
1671 adapter2_4->tx_flow_low_watermark =
1672 hdd_ctx->config->
1673 TxLbwFlowLowWaterMark;
1674 adapter2_4->
1675 tx_flow_high_watermark_offset =
1676 hdd_ctx->config->
1677 TxLbwFlowHighWaterMarkOffset;
1678 cdp_fc_ll_set_tx_pause_q_depth(soc,
1679 adapter2_4->sessionId,
1680 hdd_ctx->config->
1681 TxLbwFlowMaxQueueDepth);
1682 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1683 hdd_device_mode_to_string(
1684 adapter2_4->device_mode),
1685 adapter2_4->device_mode,
1686 channel24,
1687 adapter2_4->
1688 tx_flow_low_watermark,
1689 adapter2_4->
1690 tx_flow_low_watermark +
1691 adapter2_4->
1692 tx_flow_high_watermark_offset,
1693 hdd_ctx->config->
1694 TxLbwFlowMaxQueueDepth);
1695
1696 }
1697 }
1698 }
1699 targetChannel = 0;
1700#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1701 status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext);
1702 adapterNode = pNext;
1703 }
1704 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1705}
1706
1707/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001708 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001710 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1711 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001712 *
1713 * Return: true if IPA is enabled, false otherwise
1714 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001715static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1717{
1718 struct hdd_ipa_priv *hdd_ipa;
1719
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720 *ipa_tx_diff = 0;
1721 *ipa_rx_diff = 0;
1722
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001723 if (wlan_hdd_validate_context(hdd_ctx))
1724 return;
1725
1726 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1727
1728 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1729 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730 return;
1731 }
1732
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301733 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1735 (false == hdd_ipa->resource_loading)) {
1736 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1737 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001738 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001739 *ipa_tx_diff, *ipa_rx_diff);
1740 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301741 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742}
1743
1744/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001745 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1746 * @hdd_ctx: Global HDD context
1747 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1748 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1749 *
1750 * Return: true if IPA is enabled, false otherwise
1751 */
1752void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1753 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1754{
1755 cds_ssr_protect(__func__);
1756 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1757 cds_ssr_unprotect(__func__);
1758}
1759
1760/**
1761 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762 * @adapter: network adapter
1763 * @reason: STAT REQ Reason
1764 *
1765 * Return: None
1766 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001767static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001768{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001769 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770 struct hdd_ipa_priv *hdd_ipa;
1771
Yun Park637d6482016-10-05 10:51:33 -07001772 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001773 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001775 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1776
1777 if (wlan_hdd_validate_context(hdd_ctx))
1778 return;
1779
1780 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1781 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1782 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783 return;
1784 }
1785
Yun Parkb187d542016-11-14 18:10:04 -08001786 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301787 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001788 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1789 (false == hdd_ipa->resource_loading)) {
1790 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07001791 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001792 wma_cli_set_command(
1793 (int)adapter->sessionId,
1794 (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
1795 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001796 } else {
1797 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001799}
1800
1801/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001802 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1803 * @adapter: network adapter
1804 * @reason: STAT REQ Reason
1805 *
1806 * Return: None
1807 */
1808void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1809{
1810 cds_ssr_protect(__func__);
1811 __hdd_ipa_uc_stat_request(adapter, reason);
1812 cds_ssr_unprotect(__func__);
1813}
1814
Yun Park637d6482016-10-05 10:51:33 -07001815#ifdef FEATURE_METERING
1816/**
1817 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
1818 * @adapter: network adapter
1819 * @reset_stats: reset stat countis after response
1820 *
1821 * Return: None
1822 */
1823void hdd_ipa_uc_sharing_stats_request(hdd_adapter_t *adapter,
1824 uint8_t reset_stats)
1825{
1826 hdd_context_t *pHddCtx;
1827 struct hdd_ipa_priv *hdd_ipa;
1828
1829 if (!adapter)
1830 return;
1831
1832 pHddCtx = adapter->pHddCtx;
1833 hdd_ipa = pHddCtx->hdd_ipa;
1834 if (!hdd_ipa_is_enabled(pHddCtx) ||
1835 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1836 return;
1837 }
1838
1839 HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats);
1840 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
1841 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1842 (false == hdd_ipa->resource_loading)) {
1843 qdf_mutex_release(&hdd_ipa->ipa_lock);
1844 wma_cli_set_command(
1845 (int)adapter->sessionId,
1846 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
1847 reset_stats, VDEV_CMD);
1848 } else {
1849 qdf_mutex_release(&hdd_ipa->ipa_lock);
1850 }
1851}
1852
1853/**
1854 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
1855 * @adapter: network adapter
1856 * @set_quota: when 1, FW starts quota monitoring
1857 * @quota_bytes: quota limit in bytes
1858 *
1859 * Return: None
1860 */
1861void hdd_ipa_uc_set_quota(hdd_adapter_t *adapter, uint8_t set_quota,
1862 uint64_t quota_bytes)
1863{
1864 hdd_context_t *pHddCtx;
1865 struct hdd_ipa_priv *hdd_ipa;
1866
1867 if (!adapter)
1868 return;
1869
1870 pHddCtx = adapter->pHddCtx;
1871 hdd_ipa = pHddCtx->hdd_ipa;
1872 if (!hdd_ipa_is_enabled(pHddCtx) ||
1873 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1874 return;
1875 }
1876
1877 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
1878 set_quota, quota_bytes);
1879
1880 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
1881 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1882 (false == hdd_ipa->resource_loading)) {
1883 qdf_mutex_release(&hdd_ipa->ipa_lock);
1884 wma_cli_set_command(
1885 (int)adapter->sessionId,
1886 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
1887 (set_quota ? quota_bytes : 0), VDEV_CMD);
1888 } else {
1889 qdf_mutex_release(&hdd_ipa->ipa_lock);
1890 }
1891}
1892#endif
1893
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001894/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1896 * @hdd_ipa: Global HDD IPA context
1897 * @sta_add: Should station be added
1898 * @sta_id: ID of the station being queried
1899 *
1900 * Return: true if the station was found
1901 */
1902static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1903 bool sta_add, uint8_t sta_id)
1904{
1905 bool sta_found = false;
1906 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001907
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1909 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1910 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1911 sta_found = true;
1912 break;
1913 }
1914 }
1915 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301916 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001917 "%s: STA ID %d already exist, cannot add",
1918 __func__, sta_id);
1919 return sta_found;
1920 }
1921 if (sta_add) {
1922 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1923 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1924 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1925 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1926 return sta_found;
1927 }
1928 }
1929 }
1930 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301931 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001932 "%s: STA ID %d does not exist, cannot delete",
1933 __func__, sta_id);
1934 return sta_found;
1935 }
1936 if (!sta_add) {
1937 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1938 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1939 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1940 hdd_ipa->assoc_stas_map[idx].is_reserved =
1941 false;
1942 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1943 return sta_found;
1944 }
1945 }
1946 }
1947 return sta_found;
1948}
1949
1950/**
1951 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1952 * @hdd_ipa: Global HDD IPA context
1953 *
1954 * Return: 0 on success, negative errno if error
1955 */
1956static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1957{
1958 int result;
1959 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001960 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001961
1962 /* ACTIVATE TX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001963 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001964 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1965 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001966 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1967 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301968 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001969 "%s: Enable TX PIPE fail, code %d",
1970 __func__, result);
1971 return result;
1972 }
1973 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1974 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301975 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001976 "%s: Resume TX PIPE fail, code %d",
1977 __func__, result);
1978 return result;
1979 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001980 cdp_ipa_set_active(soc,
1981 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1982 true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983
1984 /* ACTIVATE RX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001985 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001986 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1987 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001988 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1989 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301990 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 "%s: Enable RX PIPE fail, code %d",
1992 __func__, result);
1993 return result;
1994 }
1995 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1996 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301997 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998 "%s: Resume RX PIPE fail, code %d",
1999 __func__, result);
2000 return result;
2001 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002002 cdp_ipa_set_active(soc,
2003 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2004 true, false);
Leo Change3e49442015-10-26 20:07:13 -07002005 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 return 0;
2007}
2008
2009/**
2010 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
2011 * @hdd_ipa: Global HDD IPA context
2012 *
2013 * Return: 0 on success, negative errno if error
2014 */
2015static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
2016{
2017 int result;
2018
Leo Change3e49442015-10-26 20:07:13 -07002019 hdd_ipa->ipa_pipes_down = true;
2020
Srinivas Girigowda97852372017-03-06 16:52:59 -08002021 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002022 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
2023 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302024 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002025 "%s: Suspend RX PIPE fail, code %d",
2026 __func__, result);
2027 return result;
2028 }
2029 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
2030 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302031 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002032 "%s: Disable RX PIPE fail, code %d",
2033 __func__, result);
2034 return result;
2035 }
2036
Srinivas Girigowda97852372017-03-06 16:52:59 -08002037 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
2039 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302040 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002041 "%s: Suspend TX PIPE fail, code %d",
2042 __func__, result);
2043 return result;
2044 }
2045 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
2046 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302047 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048 "%s: Disable TX PIPE fail, code %d",
2049 __func__, result);
2050 return result;
2051 }
2052
2053 return 0;
2054}
2055
2056/**
2057 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
2058 * @hdd_ipa: Global HDD IPA context
2059 *
2060 * Return: 0 on success, negative errno if error
2061 */
2062static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
2063{
2064 hdd_ipa->activated_fw_pipe = 0;
2065 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07002066
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002067 /* If RM feature enabled
2068 * Request PROD Resource first
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002069 * PROD resource may return sync or async manners
2070 */
Yun Park4cab6ee2015-10-27 11:43:40 -07002071 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
2072 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
2073 /* RM PROD request sync return
2074 * enable pipe immediately
2075 */
2076 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302077 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07002078 "%s: IPA WDI Pipe activation failed",
2079 __func__);
2080 hdd_ipa->resource_loading = false;
2081 return -EBUSY;
2082 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083 }
2084 } else {
2085 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07002086 * Just enabled all the PIPEs
2087 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002088 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302089 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07002090 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002091 __func__);
2092 hdd_ipa->resource_loading = false;
2093 return -EBUSY;
2094 }
2095 hdd_ipa->resource_loading = false;
2096 }
Yun Park4cab6ee2015-10-27 11:43:40 -07002097
Srinivas Girigowda97852372017-03-06 16:52:59 -08002098 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07002099 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100 return 0;
2101}
2102
2103/**
2104 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
2105 * @hdd_ipa: Global HDD IPA context
2106 *
2107 * Return: None
2108 */
2109static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
2110{
2111 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07002112 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002113
Yun Park7c4f31b2016-11-30 10:09:21 -08002114 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
2115 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2116 QDF_ASSERT(0);
2117 return;
2118 }
2119
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002120 hdd_ipa->resource_unloading = true;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002121 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW RX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002122 cdp_ipa_set_active(soc,
2123 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2124 false, false);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002125 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW TX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002126 cdp_ipa_set_active(soc,
2127 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2128 false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002129}
2130
2131/**
2132 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2133 * @context: User context registered with TL (the IPA Global context is
2134 * registered
2135 * @rxpkt: Packet containing the notification
2136 * @staid: ID of the station associated with the packet
2137 *
2138 * Return: None
2139 */
2140static void
2141hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
2142{
2143 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302144 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145
2146 /*
2147 * When SSR is going on or driver is unloading, just return.
2148 */
2149 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302150 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002151 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152
2153 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2154 return;
2155
Srinivas Girigowda97852372017-03-06 16:52:59 -08002156 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002157 __func__, event);
2158
2159 switch (event) {
2160 case IPA_RM_RESOURCE_GRANTED:
2161 /* Differed RM Granted */
2162 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302163 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002164 if ((false == hdd_ipa->resource_unloading) &&
2165 (!hdd_ipa->activated_fw_pipe)) {
2166 hdd_ipa_uc_enable_pipes(hdd_ipa);
2167 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302168 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002169 break;
2170
2171 case IPA_RM_RESOURCE_RELEASED:
2172 /* Differed RM Released */
2173 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002174 break;
2175
2176 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302177 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002178 "%s, invalid event code %d", __func__, event);
2179 break;
2180 }
2181}
2182
2183/**
2184 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2185 * @hdd_ipa: Global HDD IPA context
2186 * @event: IPA resource manager event to be deferred
2187 *
2188 * This function is called when a resource manager event is received
2189 * from firmware in interrupt context. This function will defer the
2190 * handling to the OL RX thread
2191 *
2192 * Return: None
2193 */
2194static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2195{
2196 enum ipa_rm_event event;
2197 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2198 struct uc_rm_work_struct, work);
2199 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2200 struct hdd_ipa_priv, uc_rm_work);
2201
2202 cds_ssr_protect(__func__);
2203 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002204 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002205 "%s, posted event %d", __func__, event);
2206
2207 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2208 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002209}
2210
2211/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002212 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2213 * @ipa_ctxt: hdd ipa local context
2214 *
2215 * Will handle IPA UC image loaded indication comes from IPA kernel
2216 *
2217 * Return: None
2218 */
2219static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt)
2220{
2221 struct ipa_wdi_out_params pipe_out;
2222
2223 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
2224 if (true == ipa_ctxt->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002225 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002226 __func__);
2227 return;
2228 }
2229
2230 ipa_ctxt->uc_loaded = true;
2231 /* Connect pipe */
2232 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2233 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2234 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
2235 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2236 "%s : TX PIPE Handle %d, DBPA 0x%llx",
2237 __func__, ipa_ctxt->tx_pipe_handle,
2238 (unsigned long long) pipe_out.uc_door_bell_pa);
2239
2240 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2241 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
2242 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2243 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2244 "%s : RX PIPE Handle %d, DBPA 0x%llx",
2245 __func__, ipa_ctxt->rx_pipe_handle,
2246 (unsigned long long) pipe_out.uc_door_bell_pa);
2247
2248 /* If already any STA connected, enable IPA/FW PIPEs */
2249 if (ipa_ctxt->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002250 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002251 "Client already connected, enable IPA/FW PIPEs");
2252 hdd_ipa_uc_handle_first_con(ipa_ctxt);
2253 }
2254}
2255
2256/**
Yun Park637d6482016-10-05 10:51:33 -07002257 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2258 * @hdd_ctx: Global HDD context
2259 * @op_msg: operation message received from firmware
2260 *
2261 * Return: QDF_STATUS enumeration
2262 */
2263#ifdef FEATURE_METERING
2264static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
2265 struct op_msg_type *op_msg)
2266{
2267 struct op_msg_type *msg = op_msg;
2268 struct ipa_uc_sharing_stats *uc_sharing_stats;
2269 struct ipa_uc_quota_rsp *uc_quota_rsp;
2270 struct ipa_uc_quota_ind *uc_quota_ind;
2271 struct hdd_ipa_priv *hdd_ipa;
2272 hdd_adapter_t *adapter;
2273
2274 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2275
2276 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2277 /* fill-up ipa_uc_sharing_stats structure from FW */
2278 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2279 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2280
2281 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2282 sizeof(struct ipa_uc_sharing_stats));
2283
2284 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2285
2286 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2287 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2288 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2289 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2290 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2291 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2292 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2293 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2294 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2295 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2296 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2297 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2298 /* received set quota response */
2299 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2300 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2301
2302 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2303 sizeof(struct ipa_uc_quota_rsp));
2304
2305 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2306 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2307 "%s: success=%d, quota_bytes=%llu",
2308 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2309 hdd_ipa->ipa_quota_rsp.success,
2310 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2311 hdd_ipa->ipa_quota_rsp.quota_lo);
2312 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2313 /* hit quota limit */
2314 uc_quota_ind = (struct ipa_uc_quota_ind *)
2315 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2316
2317 hdd_ipa->ipa_quota_ind.quota_bytes =
2318 uc_quota_ind->quota_bytes;
2319
2320 /* send quota exceeded indication to IPA */
2321 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2322 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2323 hdd_ipa->ipa_quota_ind.quota_bytes);
2324
2325 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2326 if (adapter)
2327 ipa_broadcast_wdi_quota_reach_ind(
2328 adapter->dev->ifindex,
2329 uc_quota_ind->quota_bytes);
2330 else
2331 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2332 "Failed quota_reach_ind: NULL adapter");
2333 } else {
2334 return QDF_STATUS_E_INVAL;
2335 }
2336
2337 return QDF_STATUS_SUCCESS;
2338}
2339#else
2340static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
2341 struct op_msg_type *op_msg)
2342{
2343 return QDF_STATUS_E_INVAL;
2344}
2345#endif
2346
2347/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002348 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2349 * @op_msg: operation message received from firmware
2350 * @usr_ctxt: user context registered with TL (we register the HDD Global
2351 * context)
2352 *
2353 * Return: None
2354 */
2355static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2356{
2357 struct op_msg_type *msg = op_msg;
2358 struct ipa_uc_fw_stats *uc_fw_stat;
2359 struct IpaHwStatsWDIInfoData_t ipa_stat;
2360 struct hdd_ipa_priv *hdd_ipa;
2361 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302362 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002363
2364 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302365 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002366 return;
2367 }
2368
2369 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302370 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002371 "%s, INVALID OPCODE %d", __func__, msg->op_code);
2372 return;
2373 }
2374
2375 hdd_ctx = (hdd_context_t *) usr_ctxt;
2376
2377 /*
2378 * When SSR is going on or driver is unloading, just return.
2379 */
2380 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302381 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302382 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002383 return;
2384 }
2385
2386 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2387
Govind Singhb6a89772016-08-12 11:23:35 +05302388 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002389 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002390
2391 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2392 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302393 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002394 hdd_ipa->activated_fw_pipe++;
2395 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2396 hdd_ipa->resource_loading = false;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002397 if (hdd_ipa->wdi_enabled == false) {
2398 hdd_ipa->wdi_enabled = true;
2399 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2400 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2401 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002402 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002403 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002404 if (hdd_ipa->pending_cons_req)
2405 ipa_rm_notify_completion(
2406 IPA_RM_RESOURCE_GRANTED,
2407 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002408 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002409 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302410 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002411 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002412 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302413 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002414 hdd_ipa->activated_fw_pipe--;
2415 if (!hdd_ipa->activated_fw_pipe) {
2416 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002417 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2418 ipa_rm_release_resource(
2419 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002420 /*
2421 * Sync return success from IPA
2422 * Enable/resume all the PIPEs
2423 */
Yun Park5b635012015-12-02 15:05:01 -08002424 hdd_ipa->resource_unloading = false;
2425 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2426 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002427 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302428 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002429 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002430 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002431 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302433 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002434 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002435 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002436 "CE RING SIZE: %d\n"
2437 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002438 (unsigned long long)res->ce_sr_base_paddr,
2439 res->ce_sr_ring_size,
2440 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302441 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002442 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002443 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002444 "COMP RING SIZE: %d\n"
2445 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002446 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002447 (unsigned long long)res->tx_comp_ring_base_paddr,
2448 res->tx_comp_ring_size,
2449 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08002450 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302451 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002452 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002453 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002454 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002455 "IND RING DBELL : 0x%llx\n"
2456 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002457 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08002458 "NUM TX FWD OK : %llu\n"
2459 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08002460 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002461 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08002462 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
2463 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002464 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08002465 hdd_ipa->stats.num_tx_fwd_ok,
2466 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302467 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002468 "==== IPA_UC WLAN_HOST CONTROL ====\n"
2469 "SAP NUM STAs: %d\n"
2470 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08002471 "CONCURRENT MODE: %s\n"
2472 "TX PIPE HDL: 0x%x\n"
2473 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002474 "RSC LOADING : %d\n"
2475 "RSC UNLOADING : %d\n"
2476 "PNDNG CNS RQT : %d",
2477 hdd_ipa->sap_num_connected_sta,
2478 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08002479 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002480 hdd_ipa->tx_pipe_handle,
2481 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08002482 hdd_ipa->resource_loading,
2483 hdd_ipa->resource_unloading,
2484 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002485
2486 /* STATs from FW */
2487 uc_fw_stat = (struct ipa_uc_fw_stats *)
2488 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302489 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002490 "==== IPA_UC WLAN_FW TX ====\n"
2491 "COMP RING BASE: 0x%x\n"
2492 "COMP RING SIZE: %d\n"
2493 "COMP RING DBELL : 0x%x\n"
2494 "COMP RING DBELL IND VAL : %d\n"
2495 "COMP RING DBELL CACHED VAL : %d\n"
2496 "COMP RING DBELL CACHED VAL : %d\n"
2497 "PKTS ENQ : %d\n"
2498 "PKTS COMP : %d\n"
2499 "IS SUSPEND : %d\n"
2500 "RSVD : 0x%x",
2501 uc_fw_stat->tx_comp_ring_base,
2502 uc_fw_stat->tx_comp_ring_size,
2503 uc_fw_stat->tx_comp_ring_dbell_addr,
2504 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2505 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2506 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2507 uc_fw_stat->tx_pkts_enqueued,
2508 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002509 uc_fw_stat->tx_is_suspend,
2510 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302511 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002512 "==== IPA_UC WLAN_FW RX ====\n"
2513 "IND RING BASE: 0x%x\n"
2514 "IND RING SIZE: %d\n"
2515 "IND RING DBELL : 0x%x\n"
2516 "IND RING DBELL IND VAL : %d\n"
2517 "IND RING DBELL CACHED VAL : %d\n"
2518 "RDY IND ADDR : 0x%x\n"
2519 "RDY IND CACHE VAL : %d\n"
2520 "RFIL IND : %d\n"
2521 "NUM PKT INDICAT : %d\n"
2522 "BUF REFIL : %d\n"
2523 "NUM DROP NO SPC : %d\n"
2524 "NUM DROP NO BUF : %d\n"
2525 "IS SUSPND : %d\n"
2526 "RSVD : 0x%x\n",
2527 uc_fw_stat->rx_ind_ring_base,
2528 uc_fw_stat->rx_ind_ring_size,
2529 uc_fw_stat->rx_ind_ring_dbell_addr,
2530 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2531 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2532 uc_fw_stat->rx_ind_ring_rdidx_addr,
2533 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2534 uc_fw_stat->rx_refill_idx,
2535 uc_fw_stat->rx_num_pkts_indicated,
2536 uc_fw_stat->rx_buf_refilled,
2537 uc_fw_stat->rx_num_ind_drop_no_space,
2538 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002539 uc_fw_stat->rx_is_suspend,
2540 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002541 /* STATs from IPA */
2542 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302543 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002544 "==== IPA_UC IPA TX ====\n"
2545 "NUM PROCD : %d\n"
2546 "CE DBELL : 0x%x\n"
2547 "NUM DBELL FIRED : %d\n"
2548 "COMP RNG FULL : %d\n"
2549 "COMP RNG EMPT : %d\n"
2550 "COMP RNG USE HGH : %d\n"
2551 "COMP RNG USE LOW : %d\n"
2552 "BAM FIFO FULL : %d\n"
2553 "BAM FIFO EMPT : %d\n"
2554 "BAM FIFO USE HGH : %d\n"
2555 "BAM FIFO USE LOW : %d\n"
2556 "NUM DBELL : %d\n"
2557 "NUM UNEXP DBELL : %d\n"
2558 "NUM BAM INT HDL : 0x%x\n"
2559 "NUM BAM INT NON-RUN : 0x%x\n"
2560 "NUM QMB INT HDL : 0x%x",
2561 ipa_stat.tx_ch_stats.num_pkts_processed,
2562 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2563 ipa_stat.tx_ch_stats.num_db_fired,
2564 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2565 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2566 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2567 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2568 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2569 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2570 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2571 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2572 ipa_stat.tx_ch_stats.num_db,
2573 ipa_stat.tx_ch_stats.num_unexpected_db,
2574 ipa_stat.tx_ch_stats.num_bam_int_handled,
2575 ipa_stat.tx_ch_stats.
2576 num_bam_int_in_non_runnning_state,
2577 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2578
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302579 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002580 "==== IPA_UC IPA RX ====\n"
2581 "MAX OST PKT : %d\n"
2582 "NUM PKT PRCSD : %d\n"
2583 "RNG RP : 0x%x\n"
2584 "COMP RNG FULL : %d\n"
2585 "COMP RNG EMPT : %d\n"
2586 "COMP RNG USE HGH : %d\n"
2587 "COMP RNG USE LOW : %d\n"
2588 "BAM FIFO FULL : %d\n"
2589 "BAM FIFO EMPT : %d\n"
2590 "BAM FIFO USE HGH : %d\n"
2591 "BAM FIFO USE LOW : %d\n"
2592 "NUM DB : %d\n"
2593 "NUM UNEXP DB : %d\n"
2594 "NUM BAM INT HNDL : 0x%x\n",
2595 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2596 ipa_stat.rx_ch_stats.num_pkts_processed,
2597 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2598 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2599 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2600 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2601 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2602 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2603 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2604 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2605 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2606 ipa_stat.rx_ch_stats.num_db,
2607 ipa_stat.rx_ch_stats.num_unexpected_db,
2608 ipa_stat.rx_ch_stats.num_bam_int_handled);
2609 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2610 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2611 /* STATs from FW */
2612 uc_fw_stat = (struct ipa_uc_fw_stats *)
2613 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302614 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002615 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2616 uc_fw_stat->tx_pkts_completed,
2617 hdd_ipa->ipa_p_tx_packets);
2618 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2619 (uc_fw_stat->rx_num_ind_drop_no_space +
2620 uc_fw_stat->rx_num_ind_drop_no_buf +
2621 uc_fw_stat->rx_num_pkts_indicated),
2622 hdd_ipa->ipa_p_rx_packets);
2623
2624 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2625 hdd_ipa->ipa_p_rx_packets =
2626 (uc_fw_stat->rx_num_ind_drop_no_space +
2627 uc_fw_stat->rx_num_ind_drop_no_buf +
2628 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302629 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002630 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2631 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2632 hdd_ipa_uc_loaded_handler(hdd_ipa);
2633 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002634 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2635 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2636 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302638 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002639}
2640
2641
2642/**
2643 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2644 * @adapter: device adapter instance
2645 * @offload_type: MCC or SCC
2646 * @enable: TX offload enable or disable
2647 *
2648 * Return: none
2649 */
2650static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002651 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002652{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002653 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002654 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002655 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002656 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002657
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002658 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002659 return;
2660
Yun Park8292dcb2016-10-07 16:46:06 -07002661 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002662 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002663
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002664 if (!iface_context) {
2665 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2666 "Interface context is NULL");
2667 return;
2668 }
2669
2670 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002671 /* IPA offload status is already set as desired */
2672 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002673 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
2674 "IPA offload status is already set",
2675 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002676 return;
2677 }
2678
Yun Park4540e862016-11-10 16:30:06 -08002679 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2680 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2681 "invalid session id: %d, offload_type=%d, enable=%d",
2682 adapter->sessionId, offload_type, enable);
2683 return;
2684 }
2685
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302686 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002687 sizeof(ipa_offload_enable_disable));
2688 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002689 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002690 ipa_offload_enable_disable.enable = enable;
2691
Srinivas Girigowda97852372017-03-06 16:52:59 -08002692 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park8292dcb2016-10-07 16:46:06 -07002693 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002694 ipa_offload_enable_disable.offload_type,
2695 ipa_offload_enable_disable.vdev_id,
2696 ipa_offload_enable_disable.enable);
2697
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302698 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002699 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2700 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302701 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002702 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2703 __func__,
2704 ipa_offload_enable_disable.offload_type,
2705 ipa_offload_enable_disable.vdev_id,
2706 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002707 } else {
2708 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002709 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002710 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002711 }
2712}
2713
2714/**
2715 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2716 * @work: uC OP work
2717 *
2718 * Return: None
2719 */
2720static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2721{
2722 struct op_msg_type *msg;
2723 struct uc_op_work_struct *uc_op_work = container_of(work,
2724 struct uc_op_work_struct, work);
2725 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2726
2727 cds_ssr_protect(__func__);
2728
2729 msg = uc_op_work->msg;
2730 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002731 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732 "%s, posted msg %d", __func__, msg->op_code);
2733
2734 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2735
2736 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002737}
2738
2739/**
2740 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2741 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2742 * @op_msg: operation message received from firmware
2743 * @hdd_ctx: Global HDD context
2744 *
2745 * Return: None
2746 */
2747static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2748{
2749 struct hdd_ipa_priv *hdd_ipa;
2750 struct op_msg_type *msg;
2751 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302752 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002753
2754 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302755 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002756 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002757
2758 msg = (struct op_msg_type *)op_msg;
2759 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2760
2761 if (unlikely(!hdd_ipa))
2762 goto end;
2763
2764 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302765 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002766 __func__, msg->op_code);
2767 goto end;
2768 }
2769
2770 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2771 if (uc_op_work->msg)
2772 /* When the same uC OPCODE is already pended, just return */
2773 goto end;
2774
2775 uc_op_work->msg = msg;
2776 schedule_work(&uc_op_work->work);
2777 return;
2778
2779end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302780 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002781}
2782
2783/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002784 * hdd_ipa_init_uc_op_work - init ipa uc op work
2785 * @work: struct work_struct
2786 * @work_handler: work_handler
2787 *
2788 * Return: none
2789 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002790static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002791 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002792{
2793 INIT_WORK(work, work_handler);
2794}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002795
Yun Park637d6482016-10-05 10:51:33 -07002796#ifdef FEATURE_METERING
2797/**
2798 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2799 * IPA calls to get WLAN stats or set quota limit.
2800 * @priv: pointer to private data registered with IPA (we register a
2801 *» pointer to the global IPA context)
2802 * @evt: the IPA event which triggered the callback
2803 * @data: data associated with the event
2804 *
2805 * Return: None
2806 */
2807static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2808 void *data)
2809{
2810 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2811 hdd_adapter_t *adapter = NULL;
2812 struct ipa_get_wdi_sap_stats *wdi_sap_stats;
2813 struct ipa_set_wifi_quota *ipa_set_quota;
2814 int ret = 0;
2815
2816 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2817 return;
2818
2819 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2820
2821 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2822
2823 switch (evt) {
2824 case IPA_GET_WDI_SAP_STATS:
2825 /* fill-up ipa_get_wdi_sap_stats structure after getting
2826 ipa_uc_fw_stats from FW */
2827 wdi_sap_stats = data;
2828
2829 if (!adapter) {
2830 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2831 "IPA uC share stats failed - no adapter");
2832 wdi_sap_stats->stats_valid = 0;
2833 return;
2834 }
2835
2836 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
2837 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
2838 hdd_ipa_uc_sharing_stats_request(adapter,
2839 wdi_sap_stats->reset_stats);
2840 ret = wait_for_completion_timeout(
2841 &hdd_ipa->ipa_uc_sharing_stats_comp,
2842 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2843 if (!ret) {
2844 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2845 "IPA uC share stats request timed out");
2846 wdi_sap_stats->stats_valid = 0;
2847 } else {
2848 wdi_sap_stats->stats_valid = 1;
2849
2850 wdi_sap_stats->ipv4_rx_packets =
2851 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2852 wdi_sap_stats->ipv4_rx_bytes =
2853 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2854 wdi_sap_stats->ipv6_rx_packets =
2855 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2856 wdi_sap_stats->ipv6_rx_bytes =
2857 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
2858 wdi_sap_stats->ipv4_tx_packets =
2859 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
2860 wdi_sap_stats->ipv4_tx_bytes =
2861 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
2862 wdi_sap_stats->ipv6_tx_packets =
2863 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
2864 wdi_sap_stats->ipv6_tx_bytes =
2865 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
2866 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2867 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2868 "IPA_GET_WDI_SAP_STATS",
2869 wdi_sap_stats->stats_valid,
2870 wdi_sap_stats->ipv4_rx_packets,
2871 wdi_sap_stats->ipv4_rx_bytes,
2872 wdi_sap_stats->ipv6_rx_packets,
2873 wdi_sap_stats->ipv6_rx_bytes,
2874 wdi_sap_stats->ipv4_tx_packets,
2875 wdi_sap_stats->ipv4_tx_bytes,
2876 wdi_sap_stats->ipv6_tx_packets,
2877 wdi_sap_stats->ipv6_tx_bytes);
2878 }
2879 break;
2880 case IPA_SET_WIFI_QUOTA:
2881 /* get ipa_set_wifi_quota structure from IPA and pass to FW
2882 through quota_exceeded field in ipa_uc_fw_stats */
2883 ipa_set_quota = data;
2884
2885 if (!adapter) {
2886 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2887 "IPA uC set quota failed - no adapter");
2888 ipa_set_quota->set_valid = 0;
2889 return;
2890 }
2891
2892 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
2893 ipa_set_quota->quota_bytes);
2894
2895 ret = wait_for_completion_timeout(
2896 &hdd_ipa->ipa_uc_set_quota_comp,
2897 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
2898 if (!ret) {
2899 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2900 "IPA uC set quota request timed out");
2901 ipa_set_quota->set_valid = 0;
2902 } else {
2903 ipa_set_quota->quota_bytes =
2904 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
2905 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
2906 ipa_set_quota->set_valid =
2907 hdd_ipa->ipa_quota_rsp.success;
2908 }
2909
2910 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
2911 ipa_set_quota->quota_bytes,
2912 ipa_set_quota->set_valid);
2913 break;
2914 }
2915}
2916
2917/**
2918 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2919 * IPA calls to get WLAN stats or set quota limit.
2920 * @priv: pointer to private data registered with IPA (we register a
2921 *» pointer to the global IPA context)
2922 * @evt: the IPA event which triggered the callback
2923 * @data: data associated with the event
2924 *
2925 * Return: None
2926 */
2927static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2928 void *data)
2929{
2930 cds_ssr_protect(__func__);
2931 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
2932 cds_ssr_unprotect(__func__);
2933}
2934
2935static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt,
2936 struct ipa_wdi_in_params *pipe_in)
2937{
2938 pipe_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb;
2939
2940 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
2941 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
2942}
2943#else
2944static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt,
2945 struct ipa_wdi_in_params *pipe_in)
2946{
2947}
2948#endif
2949
Rajeev Kumar217f2172016-01-06 18:11:55 -08002950/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002951 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2952 * @hdd_ctx: Global HDD context
2953 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302954 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002955 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002956QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002957{
2958 struct ipa_wdi_in_params pipe_in;
2959 struct ipa_wdi_out_params pipe_out;
2960 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002961 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07002962 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002963 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2964 int ret;
2965 QDF_STATUS stat = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002966
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002967 ENTER();
2968
Yun Parkbaa62862017-01-18 13:43:34 -08002969 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002970 if (!pdev || !soc) {
2971 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkbaa62862017-01-18 13:43:34 -08002972 stat = QDF_STATUS_E_FAILURE;
2973 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002974 }
Yun Parkbaa62862017-01-18 13:43:34 -08002975
2976 cdp_ipa_get_resource(soc, (void *)pdev, &ipa_ctxt->ipa_resource);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002977 if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) ||
2978 (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2979 (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2980 (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2981 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2982 "IPA UC resource alloc fail");
2983 return QDF_STATUS_E_FAILURE;
2984 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002985 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2986 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302987 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2988 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002989
Anurag Chouhanffb21542016-02-17 14:33:03 +05302990 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302991
2992 if (!cds_is_driver_recovering()) {
2993 qdf_mutex_create(&ipa_ctxt->event_lock);
2994 qdf_mutex_create(&ipa_ctxt->ipa_lock);
2995 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002996
2997 /* TX PIPE */
2998 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2999 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
3000 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
3001 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
3002 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
3003 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
3004 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
3005 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
3006 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
3007 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
3008 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
3009 pipe_in.sys.notify = hdd_ipa_i2w_cb;
3010 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003011 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3012 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003013 pipe_in.sys.keep_ipa_awake = true;
3014 }
3015
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003016 pipe_in.u.dl.comp_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003017 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003018 pipe_in.u.dl.comp_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003019 ipa_ctxt->ipa_resource.tx_comp_ring_size *
3020 sizeof(qdf_dma_addr_t);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003021 pipe_in.u.dl.ce_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003022 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003023 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
3024 pipe_in.u.dl.ce_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003025 ipa_ctxt->ipa_resource.ce_sr_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003026 pipe_in.u.dl.num_tx_buffers =
Yun Parkbaa62862017-01-18 13:43:34 -08003027 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003028
Yun Parkbaa62862017-01-18 13:43:34 -08003029 qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in,
3030 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003031 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08003032 IPA_CLIENT_WLAN1_CONS);
3033
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003034 if (true == ipa_ctxt->uc_loaded) {
3035 /* Connect WDI IPA PIPE */
Yun Parkbaa62862017-01-18 13:43:34 -08003036 ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
3037 if (ret) {
3038 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3039 "ipa_connect_wdi_pipe falied for Tx: ret=%d",
3040 ret);
3041 stat = QDF_STATUS_E_FAILURE;
3042 goto fail_return;
3043 }
Yun Park637d6482016-10-05 10:51:33 -07003044
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003045 /* Micro Controller Doorbell register */
Srinivas Girigowda97852372017-03-06 16:52:59 -08003046 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003047 "CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
3048 (unsigned int)pipe_out.uc_door_bell_pa,
3049 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003050 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Yun Parkbaa62862017-01-18 13:43:34 -08003051
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003052 /* WLAN TX PIPE Handle */
3053 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08003054 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003055 "TX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x, %s %d, %s %d, %s 0x%x",
3056 "comp_ring_base_pa",
3057 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
3058 "comp_ring_size",
3059 pipe_in.u.dl.comp_ring_size,
3060 "ce_ring_base_pa",
3061 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
3062 "ce_door_bell_pa",
3063 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
3064 "ce_ring_size",
3065 pipe_in.u.dl.ce_ring_size,
3066 "num_tx_buffers",
3067 pipe_in.u.dl.num_tx_buffers,
3068 "tx_comp_doorbell_paddr",
3069 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003070 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003071
3072 /* RX PIPE */
3073 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3074 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
3075 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
3076 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
3077 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
3078 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
3079 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
3080 sizeof(struct sps_iovec);
3081 pipe_in.sys.notify = hdd_ipa_w2i_cb;
3082 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303083 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkbaa62862017-01-18 13:43:34 -08003084 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003085 pipe_in.sys.keep_ipa_awake = true;
3086 }
3087
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003088 pipe_in.u.ul.rdy_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003089 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003090 pipe_in.u.ul.rdy_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003091 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003092 pipe_in.u.ul.rdy_ring_rp_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003093 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003094 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Yun Parkbaa62862017-01-18 13:43:34 -08003095
Yun Park637d6482016-10-05 10:51:33 -07003096 hdd_ipa_init_metering(ipa_ctxt, &pipe_in);
3097
Yun Parkbaa62862017-01-18 13:43:34 -08003098 qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in,
3099 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003100 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08003101 IPA_CLIENT_WLAN1_PROD);
3102
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003103 if (true == ipa_ctxt->uc_loaded) {
Yun Parkbaa62862017-01-18 13:43:34 -08003104 ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
3105 if (ret) {
3106 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3107 "ipa_connect_wdi_pipe falied for Rx: ret=%d",
3108 ret);
3109 stat = QDF_STATUS_E_FAILURE;
3110 goto fail_return;
3111
3112 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003113 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
3114 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08003115 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08003116 "PROD DB pipe out 0x%x TX PIPE Handle 0x%x",
3117 (unsigned int)pipe_out.uc_door_bell_pa,
3118 ipa_ctxt->tx_pipe_handle);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003119 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003120 "RX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x",
3121 "rdy_ring_base_pa",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003122 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
Yun Park637d6482016-10-05 10:51:33 -07003123 "rdy_ring_size",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003124 pipe_in.u.ul.rdy_ring_size,
Yun Park637d6482016-10-05 10:51:33 -07003125 "rdy_ring_rp_pa",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003126 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
Yun Park637d6482016-10-05 10:51:33 -07003127 "rx_ready_doorbell_paddr",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003128 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
3129 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003130
Yun Parkbaa62862017-01-18 13:43:34 -08003131 cdp_ipa_set_doorbell_paddr(soc, (void *)pdev,
3132 ipa_ctxt->tx_comp_doorbell_paddr,
3133 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003134
Yun Parkbaa62862017-01-18 13:43:34 -08003135 cdp_ipa_register_op_cb(soc, (void *)pdev,
3136 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
3137
3138 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
3139 "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x",
3140 pdev->ipa_uc_op_cb,
3141 (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr,
3142 (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003143
3144 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08003145 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Yun Parkbaa62862017-01-18 13:43:34 -08003146 hdd_ipa_uc_fw_op_event_handler);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003147 ipa_ctxt->uc_op_work[i].msg = NULL;
3148 }
3149
Yun Parkbaa62862017-01-18 13:43:34 -08003150fail_return:
3151 EXIT();
3152 return stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003153}
3154
Leo Change3e49442015-10-26 20:07:13 -07003155/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003156 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07003157 * @hdd_ctx: hdd main context
3158 *
3159 * Force shutdown IPA pipe
3160 * Independent of FW pipe status, IPA pipe shutdonw progress
3161 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3162 * independent from FW pipe status
3163 *
3164 * Return: NONE
3165 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003166static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07003167{
3168 struct hdd_ipa_priv *hdd_ipa;
3169
3170 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
3171 return;
3172
3173 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
3174 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303175 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07003176 "IPA pipes are not down yet, force shutdown");
3177 hdd_ipa_uc_disable_pipes(hdd_ipa);
3178 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003179 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Leo Change3e49442015-10-26 20:07:13 -07003180 "IPA pipes are down, do nothing");
3181 }
Leo Change3e49442015-10-26 20:07:13 -07003182}
3183
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003184/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003185 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
3186 * __hdd_ipa_uc_force_pipe_shutdown
3187 * @hdd_ctx: hdd main context
3188 *
3189 * Force shutdown IPA pipe
3190 * Independent of FW pipe status, IPA pipe shutdonw progress
3191 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3192 * independent from FW pipe status
3193 *
3194 * Return: NONE
3195 */
3196void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
3197{
3198 cds_ssr_protect(__func__);
3199 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
3200 cds_ssr_unprotect(__func__);
3201}
3202
3203/**
Govind Singh9c58eba2016-09-02 16:23:06 +05303204 * hdd_ipa_msg_free_fn() - Free an IPA message
3205 * @buff: pointer to the IPA message
3206 * @len: length of the IPA message
3207 * @type: type of IPA message
3208 *
3209 * Return: None
3210 */
3211static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
3212{
Srinivas Girigowda97852372017-03-06 16:52:59 -08003213 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05303214 ghdd_ipa->stats.num_free_msg++;
3215 qdf_mem_free(buff);
3216}
3217
Govind Singh9c58eba2016-09-02 16:23:06 +05303218/**
jge62037862016-12-09 10:44:33 +08003219 * hdd_ipa_uc_send_evt() - send event to ipa
3220 * @hdd_ctx: pointer to hdd context
3221 * @type: event type
3222 * @mac_addr: pointer to mac address
3223 *
3224 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303225 *
3226 * Return: 0 - Success
3227 */
jge62037862016-12-09 10:44:33 +08003228static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
3229 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303230{
jge62037862016-12-09 10:44:33 +08003231 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05303232 struct ipa_msg_meta meta;
3233 struct ipa_wlan_msg *msg;
3234 int ret = 0;
jge62037862016-12-09 10:44:33 +08003235
3236 meta.msg_len = sizeof(struct ipa_wlan_msg);
3237 msg = qdf_mem_malloc(meta.msg_len);
3238 if (msg == NULL) {
3239 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3240 "msg allocation failed");
3241 return -ENOMEM;
3242 }
3243
3244 meta.msg_type = type;
3245 strlcpy(msg->name, adapter->dev->name,
3246 IPA_RESOURCE_NAME_MAX);
3247 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003248 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
jge62037862016-12-09 10:44:33 +08003249 msg->name, meta.msg_type);
3250 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
3251 if (ret) {
3252 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3253 "%s: Evt: %d fail:%d",
3254 msg->name, meta.msg_type, ret);
3255 qdf_mem_free(msg);
3256 return ret;
3257 }
3258
3259 hdd_ipa->stats.num_send_msg++;
3260
3261 return ret;
3262}
3263
3264/**
3265 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3266 * @hdd_ctx: pointer to hdd adapter
3267 *
3268 * Send disconnect client event to IPA driver during SSR
3269 *
3270 * Return: 0 - Success
3271 */
3272static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
3273{
3274 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3275 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303276 int i;
3277
3278 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
3279 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
3280 continue;
3281 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08003282 (!adapter->aStaInfo[i].isDeauthInProgress) &&
3283 hdd_ipa->sap_num_connected_sta) {
3284 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
3285 adapter->aStaInfo[i].macAddrSTA.bytes);
3286 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303287 }
3288 }
3289
3290 return ret;
3291}
3292
3293/**
jge62037862016-12-09 10:44:33 +08003294 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3295 * @hdd_ctx: pointer to hdd adapter
3296 *
3297 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303298 *
3299 * Return: 0 - Success
3300 */
jge62037862016-12-09 10:44:33 +08003301
3302static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
3303{
3304 int ret = 0;
3305
3306 if (adapter->ipa_context)
3307 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3308 adapter->dev->dev_addr);
3309
3310 return ret;
3311}
3312
jge62037862016-12-09 10:44:33 +08003313/**
3314 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3315 * @hdd_ctx: pointer to hdd adapter
3316 *
3317 * Send disconnect sta event to IPA driver during SSR
3318 *
3319 * Return: 0 - Success
3320 */
3321static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
3322{
3323 hdd_station_ctx_t *pHddStaCtx;
3324 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3325 int ret = 0;
3326
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003327 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003328 hdd_ipa->sta_connected) {
3329 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
3330 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003331 pHddStaCtx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003332 }
3333
3334 return ret;
3335}
jge62037862016-12-09 10:44:33 +08003336
3337/**
3338 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3339 * @hdd_ctx: pointer to hdd context
3340 *
3341 * Send disconnect event to IPA driver during SSR
3342 *
3343 * Return: 0 - Success
3344 */
3345static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303346{
3347 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
3348 QDF_STATUS status;
3349 hdd_adapter_t *adapter;
3350 int ret = 0;
3351
Govind Singh9c58eba2016-09-02 16:23:06 +05303352 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
3353 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
3354 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08003355 if (adapter->device_mode == QDF_SAP_MODE) {
3356 hdd_ipa_uc_disconnect_client(adapter);
3357 hdd_ipa_uc_disconnect_ap(adapter);
3358 } else if (adapter->device_mode == QDF_STA_MODE) {
3359 hdd_ipa_uc_disconnect_sta(adapter);
3360 }
3361
Govind Singh9c58eba2016-09-02 16:23:06 +05303362 status = hdd_get_next_adapter(
3363 hdd_ctx, adapter_node, &next);
3364 adapter_node = next;
3365 }
3366
3367 return ret;
3368}
3369
3370/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003371 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003372 *
3373 * Deinit basic IPA UC host side to be in sync reloaded FW during
3374 * SSR
3375 *
3376 * Return: 0 - Success
3377 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003378static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003379{
3380 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3381 int idx;
3382 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303383 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003384
Arun Khandavallicc544b32017-01-30 19:52:16 +05303385 if (!hdd_ipa)
3386 return 0;
3387
3388 hdd_ctx = hdd_ipa->hdd_ctx;
3389 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003390 return 0;
3391
jge62037862016-12-09 10:44:33 +08003392 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303393 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003394
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003395 /* Clean up HDD IPA interfaces */
3396 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3397 (idx < HDD_IPA_MAX_IFACE); idx++) {
3398 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003399 if (iface_context->adapter && iface_context->adapter->magic ==
3400 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003401 hdd_ipa_cleanup_iface(iface_context);
3402 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003403 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003404 /* After SSR, wlan driver reloads FW again. But we need to protect
3405 * IPA submodule during SSR transient state. So deinit basic IPA
3406 * UC host side to be in sync with reloaded FW during SSR
3407 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08003408 if (!hdd_ipa->ipa_pipes_down)
3409 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303411 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003412 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3413 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3414 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3415 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303416 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003417
Srinivas Girigowda97852372017-03-06 16:52:59 -08003418 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Arun Khandavallicc544b32017-01-30 19:52:16 +05303419 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
3420 __func__, hdd_ipa->tx_pipe_handle);
3421 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
3422
Srinivas Girigowda97852372017-03-06 16:52:59 -08003423 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Arun Khandavallicc544b32017-01-30 19:52:16 +05303424 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
3425 __func__, hdd_ipa->rx_pipe_handle);
3426 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
3427
Guolei Bianca144d82016-11-10 11:07:42 +08003428 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3429 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3430
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003431 /* Full IPA driver cleanup not required since wlan driver is now
3432 * unloaded and reloaded after SSR.
3433 */
3434 return 0;
3435}
3436
3437/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003438 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3439 *
3440 * Deinit basic IPA UC host side to be in sync reloaded FW during
3441 * SSR
3442 *
3443 * Return: 0 - Success
3444 */
3445int hdd_ipa_uc_ssr_deinit(void)
3446{
3447 int ret;
3448
3449 cds_ssr_protect(__func__);
3450 ret = __hdd_ipa_uc_ssr_deinit();
3451 cds_ssr_unprotect(__func__);
3452
3453 return ret;
3454}
3455
3456/**
3457 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003458 *
3459 * Init basic IPA UC host side to be in sync with reloaded FW after
3460 * SSR to resume IPA UC operations
3461 *
3462 * Return: 0 - Success
3463 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303464static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003465{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003466
Arun Khandavallicc544b32017-01-30 19:52:16 +05303467 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3468 int i;
3469 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303470
3471 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3472 return 0;
3473
Arun Khandavallicc544b32017-01-30 19:52:16 +05303474 /* Create the interface context */
3475 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3476 iface_context = &hdd_ipa->iface_context[i];
3477 iface_context->hdd_ipa = hdd_ipa;
3478 iface_context->cons_client =
3479 hdd_ipa_adapter_2_client[i].cons_client;
3480 iface_context->prod_client =
3481 hdd_ipa_adapter_2_client[i].prod_client;
3482 iface_context->iface_id = i;
3483 iface_context->adapter = NULL;
3484 }
3485 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3486 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3487 hdd_ipa->vdev_offload_enabled[i] = false;
3488 }
3489
3490 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3491 hdd_ipa->resource_loading = false;
3492 hdd_ipa->resource_unloading = false;
3493 hdd_ipa->sta_connected = 0;
3494 hdd_ipa->ipa_pipes_down = true;
3495 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303496 }
3497
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003498 return 0;
3499}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003500
3501/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003502 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3503 *
3504 * Init basic IPA UC host side to be in sync with reloaded FW after
3505 * SSR to resume IPA UC operations
3506 *
3507 * Return: 0 - Success
3508 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303509int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003510{
3511 int ret;
3512
3513 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303514 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003515 cds_ssr_unprotect(__func__);
3516
3517 return ret;
3518}
3519
3520/**
3521 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08003522 * @hdd_ctx: Global HDD context
3523 * @skb: skb sent to IPA
3524 * @session_id: send packet instance session id
3525 *
3526 * Send TX packet which generated by system to IPA.
3527 * This routine only will be used for function verification
3528 *
3529 * Return: NULL packet sent to IPA properly
3530 * NULL invalid packet drop
3531 * skb packet not sent to IPA. legacy data path should handle
3532 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003533static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08003534 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07003535{
Leo Chang3bc8fed2015-11-13 10:59:47 -08003536 struct ipa_header *ipa_header;
3537 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003538 struct hdd_ipa_priv *hdd_ipa;
3539
3540 if (wlan_hdd_validate_context(hdd_ctx))
3541 return skb;
3542
3543 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003544
3545 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3546 return skb;
3547
Leo Chang07b28f62016-05-11 12:29:22 -07003548 if (!hdd_ipa)
3549 return skb;
3550
3551 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
3552 return skb;
3553
Leo Changcc923e22016-06-16 15:29:03 -07003554 if (skb_headroom(skb) <
3555 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07003556 return skb;
3557
Leo Chang3bc8fed2015-11-13 10:59:47 -08003558 ipa_header = (struct ipa_header *) skb_push(skb,
3559 sizeof(struct ipa_header));
3560 if (!ipa_header) {
3561 /* No headroom, legacy */
3562 return skb;
3563 }
3564 memset(ipa_header, 0, sizeof(*ipa_header));
3565 ipa_header->vdev_id = 0;
3566
3567 frag_header = (struct frag_header *) skb_push(skb,
3568 sizeof(struct frag_header));
3569 if (!frag_header) {
3570 /* No headroom, drop */
3571 kfree_skb(skb);
3572 return NULL;
3573 }
3574 memset(frag_header, 0, sizeof(*frag_header));
3575 frag_header->length = skb->len - sizeof(struct frag_header)
3576 - sizeof(struct ipa_header);
3577
3578 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
3579 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07003580}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003581
3582/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003583 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
3584 * @hdd_ctx: Global HDD context
3585 * @skb: skb sent to IPA
3586 * @session_id: send packet instance session id
3587 *
3588 * Send TX packet which generated by system to IPA.
3589 * This routine only will be used for function verification
3590 *
3591 * Return: NULL packet sent to IPA properly
3592 * NULL invalid packet drop
3593 * skb packet not sent to IPA. legacy data path should handle
3594 */
3595struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
3596 struct sk_buff *skb, uint8_t session_id)
3597{
3598 struct sk_buff *ret;
3599
3600 cds_ssr_protect(__func__);
3601 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
3602 cds_ssr_unprotect(__func__);
3603
3604 return ret;
3605}
3606
3607/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003608 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3609 * @work: scheduled work
3610 *
3611 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3612 * not want to immediately release the wake lock since the system
3613 * would then potentially try to suspend when there is a healthy data
3614 * rate. Deferred work is scheduled and this function handles the
3615 * work. When this function is called, if the IPA resource is still
3616 * released then we release the wake lock.
3617 *
3618 * Return: None
3619 */
3620static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3621{
3622 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3623 struct hdd_ipa_priv,
3624 wake_lock_work);
3625
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303626 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003627
3628 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3629 goto end;
3630
3631 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303632 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003633 WIFI_POWER_EVENT_WAKELOCK_IPA);
3634
3635end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303636 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003637}
3638
3639/**
3640 * hdd_ipa_rm_request() - Request resource from IPA
3641 * @hdd_ipa: Global HDD IPA context
3642 *
3643 * Return: 0 on success, negative errno on error
3644 */
3645static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3646{
3647 int ret = 0;
3648
3649 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3650 return 0;
3651
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303652 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003653
3654 switch (hdd_ipa->rm_state) {
3655 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303656 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003657 return 0;
3658 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303659 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003660 return -EINPROGRESS;
3661 case HDD_IPA_RM_RELEASED:
3662 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3663 break;
3664 }
3665
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303666 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003667
3668 ret = ipa_rm_inactivity_timer_request_resource(
3669 IPA_RM_RESOURCE_WLAN_PROD);
3670
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303671 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003672 if (ret == 0) {
3673 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3674 hdd_ipa->stats.num_rm_grant_imm++;
3675 }
3676
3677 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3678 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303679 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003680 WIFI_POWER_EVENT_WAKELOCK_IPA);
3681 hdd_ipa->wake_lock_released = false;
3682 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303683 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684
3685 return ret;
3686}
3687
3688/**
3689 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3690 * @hdd_ipa: Global HDD IPA context
3691 *
3692 * Return: 0 if resources released, negative errno otherwise
3693 */
3694static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3695{
3696 int ret = 0;
3697
3698 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3699 return 0;
3700
3701 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3702 return -EAGAIN;
3703
3704 spin_lock_bh(&hdd_ipa->q_lock);
3705 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
3706 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
3707 spin_unlock_bh(&hdd_ipa->q_lock);
3708 return -EAGAIN;
3709 }
3710 spin_unlock_bh(&hdd_ipa->q_lock);
3711
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303712 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003713
Nirav Shahcbc6d722016-03-01 16:24:53 +05303714 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303715 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003716 return -EAGAIN;
3717 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303718 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003719
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303720 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003721 switch (hdd_ipa->rm_state) {
3722 case HDD_IPA_RM_GRANTED:
3723 break;
3724 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303725 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003726 return -EINPROGRESS;
3727 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303728 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003729 return 0;
3730 }
3731
3732 /* IPA driver returns immediately so set the state here to avoid any
3733 * race condition.
3734 */
3735 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3736 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303737 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003738
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003739 ret = ipa_rm_inactivity_timer_release_resource(
3740 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003741
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303742 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003743 if (unlikely(ret != 0)) {
3744 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3745 WARN_ON(1);
3746 }
3747
3748 /*
3749 * If wake_lock is released immediately, kernel would try to suspend
3750 * immediately as well, Just avoid ping-pong between suspend-resume
3751 * while there is healthy amount of data transfer going on by
3752 * releasing the wake_lock after some delay.
3753 */
3754 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3755 msecs_to_jiffies
3756 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3757
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303758 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003759
3760 return ret;
3761}
3762
3763/**
3764 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3765 * @user_data: user data registered with IPA
3766 * @event: the IPA resource manager event that occurred
3767 * @data: the data associated with the event
3768 *
3769 * Return: None
3770 */
3771static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3772 unsigned long data)
3773{
3774 struct hdd_ipa_priv *hdd_ipa = user_data;
3775
3776 if (unlikely(!hdd_ipa))
3777 return;
3778
3779 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3780 return;
3781
Srinivas Girigowda97852372017-03-06 16:52:59 -08003782 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003783
3784 switch (event) {
3785 case IPA_RM_RESOURCE_GRANTED:
3786 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3787 /* RM Notification comes with ISR context
3788 * it should be serialized into work queue to avoid
3789 * ISR sleep problem
3790 */
3791 hdd_ipa->uc_rm_work.event = event;
3792 schedule_work(&hdd_ipa->uc_rm_work.work);
3793 break;
3794 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303795 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003796 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303797 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003798 hdd_ipa->stats.num_rm_grant++;
3799 break;
3800
3801 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003802 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003803 hdd_ipa->resource_unloading = false;
3804 break;
3805
3806 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303807 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003808 break;
3809 }
3810}
3811
3812/**
3813 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3814 *
3815 * Callback function registered with IPA that is called when IPA wants
3816 * to release the WLAN consumer resource
3817 *
3818 * Return: 0 if the request is granted, negative errno otherwise
3819 */
3820static int hdd_ipa_rm_cons_release(void)
3821{
3822 return 0;
3823}
3824
3825/**
3826 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3827 *
3828 * Callback function registered with IPA that is called when IPA wants
3829 * to access the WLAN consumer resource
3830 *
3831 * Return: 0 if the request is granted, negative errno otherwise
3832 */
3833static int hdd_ipa_rm_cons_request(void)
3834{
Yun Park4d8b60a2015-10-22 13:59:32 -07003835 int ret = 0;
3836
3837 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303838 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003839 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003840 __func__);
3841 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003842 ret = -EINPROGRESS;
3843 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303844 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003845 "%s: IPA resource unloading in progress",
3846 __func__);
3847 ghdd_ipa->pending_cons_req = true;
3848 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003849 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003850
3851 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003852}
3853
3854/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003855 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003856 * @hdd_ctx: Global HDD context
3857 * @tx_packets: Number of packets transmitted in the last sample period
3858 * @rx_packets: Number of packets received in the last sample period
3859 *
3860 * Return: 0 on success, negative errno on error
3861 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003862static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003863 uint64_t rx_packets)
3864{
3865 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003866 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003867 struct ipa_rm_perf_profile profile;
3868 int ret;
3869
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003870 if (wlan_hdd_validate_context(hdd_ctx))
3871 return 0;
3872
3873 hdd_ipa = hdd_ctx->hdd_ipa;
3874
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003875 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3876 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3877 return 0;
3878
3879 memset(&profile, 0, sizeof(profile));
3880
3881 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3882 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3883 else if (tx_packets >
3884 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3885 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3886 else
3887 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3888
3889 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3890 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3891 else if (rx_packets >
3892 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3893 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3894 else
3895 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3896
Yun Parkec845302016-12-15 09:22:57 -08003897 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003898 "CONS perf curr: %d, next: %d",
3899 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003900 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003901 "PROD perf curr: %d, next: %d",
3902 hdd_ipa->curr_prod_bw, next_prod_bw);
3903
3904 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003905 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003906 hdd_ipa->curr_cons_bw, next_cons_bw);
3907 profile.max_supported_bandwidth_mbps = next_cons_bw;
3908 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3909 &profile);
3910 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003911 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003912
3913 return ret;
3914 }
3915 hdd_ipa->curr_cons_bw = next_cons_bw;
3916 hdd_ipa->stats.num_cons_perf_req++;
3917 }
3918
3919 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003920 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003921 hdd_ipa->curr_prod_bw, next_prod_bw);
3922 profile.max_supported_bandwidth_mbps = next_prod_bw;
3923 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3924 &profile);
3925 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003926 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927 return ret;
3928 }
3929 hdd_ipa->curr_prod_bw = next_prod_bw;
3930 hdd_ipa->stats.num_prod_perf_req++;
3931 }
3932
3933 return 0;
3934}
3935
3936/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003937 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3938 * @hdd_ctx: Global HDD context
3939 * @tx_packets: Number of packets transmitted in the last sample period
3940 * @rx_packets: Number of packets received in the last sample period
3941 *
3942 * Return: 0 on success, negative errno on error
3943 */
3944int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3945 uint64_t rx_packets)
3946{
3947 int ret;
3948
3949 cds_ssr_protect(__func__);
3950 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3951 cds_ssr_unprotect(__func__);
3952
3953 return ret;
3954}
3955
3956/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003957 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3958 * @work: struct work_struct
3959 * @work_handler: work_handler
3960 *
3961 * Return: none
3962 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003963static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3964 work_func_t work_handler)
3965{
3966 INIT_WORK(work, work_handler);
3967}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003968
3969/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003970 * hdd_ipa_setup_rm() - Setup IPA resource management
3971 * @hdd_ipa: Global HDD IPA context
3972 *
3973 * Return: 0 on success, negative errno on error
3974 */
3975static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3976{
3977 struct ipa_rm_create_params create_params = { 0 };
3978 int ret;
3979
3980 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3981 return 0;
3982
Rajeev Kumar217f2172016-01-06 18:11:55 -08003983 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3984 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003985 memset(&create_params, 0, sizeof(create_params));
3986 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3987 create_params.reg_params.user_data = hdd_ipa;
3988 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3989 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3990
3991 ret = ipa_rm_create_resource(&create_params);
3992 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303993 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003994 "Create RM resource failed: %d", ret);
3995 goto setup_rm_fail;
3996 }
3997
3998 memset(&create_params, 0, sizeof(create_params));
3999 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
4000 create_params.request_resource = hdd_ipa_rm_cons_request;
4001 create_params.release_resource = hdd_ipa_rm_cons_release;
4002 create_params.floor_voltage = IPA_VOLTAGE_SVS;
4003
4004 ret = ipa_rm_create_resource(&create_params);
4005 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304006 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004007 "Create RM CONS resource failed: %d", ret);
4008 goto delete_prod;
4009 }
4010
4011 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
4012 IPA_RM_RESOURCE_APPS_CONS);
4013
4014 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
4015 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
4016 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304017 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004018 ret);
4019 goto timer_init_failed;
4020 }
4021
4022 /* Set the lowest bandwidth to start with */
4023 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
4024
4025 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304026 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004027 "Set perf level failed: %d", ret);
4028 goto set_perf_failed;
4029 }
4030
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304031 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004032 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
4033 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304034 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004035 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
4036 hdd_ipa->wake_lock_released = true;
4037 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
4038
4039 return ret;
4040
4041set_perf_failed:
4042 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4043
4044timer_init_failed:
4045 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4046
4047delete_prod:
4048 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4049
4050setup_rm_fail:
4051 return ret;
4052}
4053
4054/**
4055 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
4056 * @hdd_ipa: Global HDD IPA context
4057 *
4058 * Destroys all resources associated with the IPA resource manager
4059 *
4060 * Return: None
4061 */
4062static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
4063{
4064 int ret;
4065
4066 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4067 return;
4068
4069 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304070 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071
4072#ifdef WLAN_OPEN_SOURCE
4073 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
4074#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304075 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004076
4077 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4078
4079 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4080 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304081 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004082 "RM PROD resource delete failed %d", ret);
4083
4084 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4085 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304086 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004087 "RM CONS resource delete failed %d", ret);
4088}
4089
4090/**
4091 * hdd_ipa_send_skb_to_network() - Send skb to kernel
4092 * @skb: network buffer
4093 * @adapter: network adapter
4094 *
4095 * Called when a network buffer is received which should not be routed
4096 * to the IPA module.
4097 *
4098 * Return: None
4099 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304100static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004101 hdd_adapter_t *adapter)
4102{
4103 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4104 unsigned int cpu_index;
4105
4106 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004107 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004108 adapter);
4109 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004110 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004111 return;
4112 }
4113
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004114 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004116 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004117 return;
4118 }
4119
4120 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
4121 skb->dev = adapter->dev;
4122 skb->protocol = eth_type_trans(skb, skb->dev);
4123 skb->ip_summed = CHECKSUM_NONE;
4124
4125 cpu_index = wlan_hdd_get_cpu();
4126
4127 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
4128 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
4129 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
4130 else
4131 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
4132
4133 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
4134 adapter->dev->last_rx = jiffies;
4135}
4136
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004137/**
Leo Chang69c39692016-10-12 20:11:12 -07004138 * hdd_ipa_forward() - handle packet forwarding to wlan tx
4139 * @hdd_ipa: pointer to hdd ipa context
4140 * @adapter: network adapter
4141 * @skb: data pointer
4142 *
4143 * if exception packet has set forward bit, copied new packet should be
4144 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
4145 * put into pm queue and tx procedure will be differed
4146 *
4147 * Return: None
4148 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07004149static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
4150 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07004151{
Leo Chang69c39692016-10-12 20:11:12 -07004152 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
4153
Leo Chang69c39692016-10-12 20:11:12 -07004154 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
4155 /* WLAN subsystem is in suspend, put int queue */
4156 if (hdd_ipa->suspended) {
4157 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4158 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4159 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004160 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
4161 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07004162 pm_tx_cb->exception = true;
4163 pm_tx_cb->adapter = adapter;
4164 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004165 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07004166 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4167 hdd_ipa->stats.num_tx_queued++;
4168 } else {
4169 /* Resume, put packet into WLAN TX */
4170 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004171 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07004172 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4173 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08004174 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07004175 } else {
Yun Parkb187d542016-11-14 18:10:04 -08004176 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07004177 hdd_ipa->ipa_tx_forward++;
4178 }
4179 }
4180}
4181
4182/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004183 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
4184 * @hdd_ipa: pointer to HDD IPA struct
4185 * @adapter: hdd adapter pointer
4186 * @desc: Firmware descriptor
4187 * @skb: Data buffer
4188 *
4189 * Return:
4190 * HDD_IPA_FORWARD_PKT_NONE
4191 * HDD_IPA_FORWARD_PKT_DISCARD
4192 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
4193 *
4194 */
4195
4196static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
4197 struct hdd_ipa_priv *hdd_ipa,
4198 hdd_adapter_t *adapter,
4199 uint8_t desc,
4200 qdf_nbuf_t skb)
4201{
4202 int ret = HDD_IPA_FORWARD_PKT_NONE;
4203
4204 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304205 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004206 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
4207 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304208 /* Drop the packet*/
4209 hdd_ipa->stats.num_tx_fwd_err++;
4210 kfree_skb(skb);
4211 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4212 return ret;
4213 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004214 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
4215 "Forward packet to Tx (fw_desc=%d)", desc);
4216 hdd_ipa->ipa_tx_forward++;
4217
4218 if ((desc & FW_RX_DESC_DISCARD_M)) {
4219 hdd_ipa_forward(hdd_ipa, adapter, skb);
4220 hdd_ipa->ipa_rx_internel_drop_count++;
4221 hdd_ipa->ipa_rx_discard++;
4222 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4223 } else {
4224 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004225
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004226 if (cloned_skb)
4227 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
4228 else
4229 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4230 "%s: tx skb alloc failed",
4231 __func__);
4232 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
4233 }
4234 }
4235
4236 return ret;
4237}
4238
4239/**
Yun Park637d6482016-10-05 10:51:33 -07004240 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004241 * @priv: pointer to private data registered with IPA (we register a
4242 * pointer to the global IPA context)
4243 * @evt: the IPA event which triggered the callback
4244 * @data: data associated with the event
4245 *
4246 * Return: None
4247 */
Yun Parkf8d6a122016-10-11 15:49:43 -07004248static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004249 unsigned long data)
4250{
4251 struct hdd_ipa_priv *hdd_ipa = NULL;
4252 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304253 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 uint8_t iface_id;
4255 uint8_t session_id;
4256 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07004258 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004259
4260 hdd_ipa = (struct hdd_ipa_priv *)priv;
4261
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08004262 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
4263 return;
4264
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004265 switch (evt) {
4266 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05304267 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07004268
4269 /*
4270 * When SSR is going on or driver is unloading,
4271 * just drop the packets.
4272 */
4273 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4274 if (0 != status) {
4275 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4276 "Invalid context: drop packet");
4277 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4278 kfree_skb(skb);
4279 return;
4280 }
4281
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004282 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4283 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004284 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004285 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004286 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4287 session_id, iface_id);
4288 } else {
4289 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4290 }
4291
4292 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304293 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004294 "IPA_RECEIVE: Invalid iface_id: %u",
4295 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004296 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004297 "w2i -- skb",
4298 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004299 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004300 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004301 return;
4302 }
4303
4304 iface_context = &hdd_ipa->iface_context[iface_id];
4305 adapter = iface_context->adapter;
4306
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304307 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004308 "w2i -- skb",
4309 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004310 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4311 hdd_ipa->stats.num_rx_excep++;
4312 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4313 } else {
4314 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4315 }
4316
4317 iface_context->stats.num_rx_ipa_excep++;
4318
4319 /* Disable to forward Intra-BSS Rx packets when
4320 * ap_isolate=1 in hostapd.conf
4321 */
Yun Park046101c2016-09-02 15:32:14 -07004322 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004323 /*
4324 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4325 * all Rx packets to IPA uC, which need to be forwarded
4326 * to other interface.
4327 * And, IPA driver will send back to WLAN host driver
4328 * through exception pipe with fw_desc field set by FW.
4329 * Here we are checking fw_desc field for FORWARD bit
4330 * set, and forward to Tx. Then copy to kernel stack
4331 * only when DISCARD bit is not set.
4332 */
4333 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004334 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4335 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4336 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004337 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004338 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004339 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 "Intra-BSS FWD is disabled-skip forward to Tx");
4341 }
4342
4343 hdd_ipa_send_skb_to_network(skb, adapter);
4344 break;
4345
4346 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304347 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004348 "w2i cb wrong event: 0x%x", evt);
4349 return;
4350 }
4351}
4352
4353/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004354 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4355 * @priv: pointer to private data registered with IPA (we register a
4356 * pointer to the global IPA context)
4357 * @evt: the IPA event which triggered the callback
4358 * @data: data associated with the event
4359 *
4360 * Return: None
4361 */
4362static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
4363 unsigned long data)
4364{
4365 cds_ssr_protect(__func__);
4366 __hdd_ipa_w2i_cb(priv, evt, data);
4367 cds_ssr_unprotect(__func__);
4368}
4369
4370/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004371 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4372 * @skb: packet buffer which was transmitted
4373 *
4374 * Return: None
4375 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304376void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004377{
4378 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4379
Govind Singhb6a89772016-08-12 11:23:35 +05304380 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05304381 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004382 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304383 ipa_free_skb((struct ipa_rx_data *)
4384 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004385
4386 hdd_ipa->stats.num_tx_comp_cnt++;
4387
4388 atomic_dec(&hdd_ipa->tx_ref_cnt);
4389
4390 hdd_ipa_rm_try_release(hdd_ipa);
4391}
4392
4393/**
4394 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4395 * @iface_context: interface-specific IPA context
4396 * @ipa_tx_desc: packet data descriptor
4397 *
4398 * Return: None
4399 */
4400static void hdd_ipa_send_pkt_to_tl(
4401 struct hdd_ipa_iface_context *iface_context,
4402 struct ipa_rx_data *ipa_tx_desc)
4403{
4404 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004405 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304406 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004407
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304408 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004409 adapter = iface_context->adapter;
4410 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304411 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004412 ipa_free_skb(ipa_tx_desc);
4413 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304414 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004415 hdd_ipa_rm_try_release(hdd_ipa);
4416 return;
4417 }
4418
4419 /*
4420 * During CAC period, data packets shouldn't be sent over the air so
4421 * drop all the packets here
4422 */
4423 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4424 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304425 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004426 iface_context->stats.num_tx_cac_drop++;
4427 hdd_ipa_rm_try_release(hdd_ipa);
4428 return;
4429 }
4430
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004431 ++adapter->stats.tx_packets;
4432
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304433 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004434
4435 skb = ipa_tx_desc->skb;
4436
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304437 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304438 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004439 /* FIXME: This is broken. No such field in cb any more:
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08004440 * NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb;
4441 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004442 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304443 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004444 ipa_tx_desc->dma_addr
4445 + HDD_IPA_WLAN_FRAG_HEADER
4446 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004447 ipa_tx_desc->skb->len -=
4448 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4449 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304450 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004451
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004452 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304453 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004454
4455 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
4456
Leo Changfdb45c32016-10-28 11:09:23 -07004457 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004458 (struct cdp_vdev *)iface_context->tl_context,
4459 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004460 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304461 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004462 ipa_free_skb(ipa_tx_desc);
4463 iface_context->stats.num_tx_err++;
4464 hdd_ipa_rm_try_release(hdd_ipa);
4465 return;
4466 }
4467
4468 atomic_inc(&hdd_ipa->tx_ref_cnt);
4469
4470 iface_context->stats.num_tx++;
4471
4472}
4473
4474/**
Leo Chang11545d62016-10-17 14:53:50 -07004475 * hdd_ipa_is_present() - get IPA hw status
4476 * @hdd_ctx: pointer to hdd context
4477 *
4478 * ipa_uc_reg_rdyCB is not directly designed to check
4479 * ipa hw status. This is an undocumented function which
4480 * has confirmed with IPA team.
4481 *
4482 * Return: true - ipa hw present
4483 * false - ipa hw not present
4484 */
4485bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
4486{
4487 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004488 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004489 return true;
4490 else
4491 return false;
4492}
4493
4494/**
Leo Chang69c39692016-10-12 20:11:12 -07004495 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004496 * @work: pointer to the scheduled work
4497 *
4498 * Called during PM resume to send packets to TL which were queued
4499 * while host was in the process of suspending.
4500 *
4501 * Return: None
4502 */
Leo Chang69c39692016-10-12 20:11:12 -07004503static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004504{
4505 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4506 struct hdd_ipa_priv,
4507 pm_work);
4508 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304509 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004510 uint32_t dequeued = 0;
4511
Leo Chang69c39692016-10-12 20:11:12 -07004512 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4513 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304514 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304515 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4516 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304517 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004518
4519 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004520 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004521 if (pm_tx_cb->exception) {
4522 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4523 "FLUSH EXCEPTION");
4524 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
4525 } else {
4526 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004527 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004528 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304529 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004530 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304531 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004532 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4533 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004534
4535 hdd_ipa->stats.num_tx_dequeued += dequeued;
4536 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4537 hdd_ipa->stats.num_max_pm_queue = dequeued;
4538}
4539
4540/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004541 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004542 * @priv: pointer to private data registered with IPA (we register a
4543 * pointer to the interface-specific IPA context)
4544 * @evt: the IPA event which triggered the callback
4545 * @data: data associated with the event
4546 *
4547 * Return: None
4548 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004549static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004550 unsigned long data)
4551{
4552 struct hdd_ipa_priv *hdd_ipa = NULL;
4553 struct ipa_rx_data *ipa_tx_desc;
4554 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304555 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004556 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304557 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004558
Mukul Sharma81661ae2015-10-30 20:26:02 +05304559 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004560 ipa_tx_desc = (struct ipa_rx_data *)data;
4561 hdd_ipa = iface_context->hdd_ipa;
4562
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004564 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4565 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004566 iface_context->stats.num_tx_drop++;
4567 return;
4568 }
4569
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004570 /*
4571 * When SSR is going on or driver is unloading, just drop the packets.
4572 * During SSR, there is no use in queueing the packets as STA has to
4573 * connect back any way
4574 */
4575 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304576 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004577 ipa_free_skb(ipa_tx_desc);
4578 iface_context->stats.num_tx_drop++;
4579 return;
4580 }
4581
4582 skb = ipa_tx_desc->skb;
4583
Yun Parkb187d542016-11-14 18:10:04 -08004584 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4585 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004586
4587 /*
4588 * If PROD resource is not requested here then there may be cases where
4589 * IPA hardware may be clocked down because of not having proper
4590 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4591 * workaround to request PROD resource while data is going over CONS
4592 * pipe to prevent the IPA hardware clockdown.
4593 */
4594 hdd_ipa_rm_request(hdd_ipa);
4595
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304596 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004597 /*
4598 * If host is still suspended then queue the packets and these will be
4599 * drained later when resume completes. When packet is arrived here and
4600 * host is suspended, this means that there is already resume is in
4601 * progress.
4602 */
4603 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304604 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004605 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4606 pm_tx_cb->iface_context = iface_context;
4607 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304608 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004609 hdd_ipa->stats.num_tx_queued++;
4610
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304611 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004612 return;
4613 }
4614
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304615 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004616
4617 /*
4618 * If we are here means, host is not suspended, wait for the work queue
4619 * to finish.
4620 */
4621#ifdef WLAN_OPEN_SOURCE
4622 flush_work(&hdd_ipa->pm_work);
4623#endif
4624
4625 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4626}
4627
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004628/*
4629 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4630 * @priv: pointer to private data registered with IPA (we register a
4631 * pointer to the interface-specific IPA context)
4632 * @evt: the IPA event which triggered the callback
4633 * @data: data associated with the event
4634 *
4635 * Return: None
4636 */
4637static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
4638 unsigned long data)
4639{
4640 cds_ssr_protect(__func__);
4641 __hdd_ipa_i2w_cb(priv, evt, data);
4642 cds_ssr_unprotect(__func__);
4643}
4644
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004645/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004646 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004647 * @hdd_ctx: Global HDD context
4648 *
4649 * Return: 0 on success, negativer errno on error
4650 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004651static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004652{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004653 struct hdd_ipa_priv *hdd_ipa;
4654
4655 if (wlan_hdd_validate_context(hdd_ctx))
4656 return 0;
4657
4658 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004659
4660 if (!hdd_ipa_is_enabled(hdd_ctx))
4661 return 0;
4662
4663 /*
4664 * Check if IPA is ready for suspend, If we are here means, there is
4665 * high chance that suspend would go through but just to avoid any race
4666 * condition after suspend started, these checks are conducted before
4667 * allowing to suspend.
4668 */
4669 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4670 return -EAGAIN;
4671
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304672 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004673
4674 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304675 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004676 return -EAGAIN;
4677 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304678 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004679
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304680 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004681 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304682 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004683
4684 return 0;
4685}
4686
4687/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004688 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4689 * @hdd_ctx: Global HDD context
4690 *
4691 * Return: 0 on success, negativer errno on error
4692 */
4693int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4694{
4695 int ret;
4696
4697 cds_ssr_protect(__func__);
4698 ret = __hdd_ipa_suspend(hdd_ctx);
4699 cds_ssr_unprotect(__func__);
4700
4701 return ret;
4702}
4703
4704/**
4705 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004706 * hdd_ctx: Global HDD context
4707 *
4708 * Return: 0 on success, negative errno on error
4709 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004710static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004711{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004712 struct hdd_ipa_priv *hdd_ipa;
4713
4714 if (wlan_hdd_validate_context(hdd_ctx))
4715 return 0;
4716
4717 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004718
4719 if (!hdd_ipa_is_enabled(hdd_ctx))
4720 return 0;
4721
4722 schedule_work(&hdd_ipa->pm_work);
4723
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304724 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004725 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304726 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004727
4728 return 0;
4729}
4730
4731/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004732 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4733 * hdd_ctx: Global HDD context
4734 *
4735 * Return: 0 on success, negative errno on error
4736 */
4737int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4738{
4739 int ret;
4740
4741 cds_ssr_protect(__func__);
4742 ret = __hdd_ipa_resume(hdd_ctx);
4743 cds_ssr_unprotect(__func__);
4744
4745 return ret;
4746}
4747
4748/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004749 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4750 * @hdd_ipa: Global HDD IPA context
4751 *
4752 * Return: 0 on success, negative errno on error
4753 */
4754static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4755{
4756 int i, ret = 0;
4757 struct ipa_sys_connect_params *ipa;
4758 uint32_t desc_fifo_sz;
4759
4760 /* The maximum number of descriptors that can be provided to a BAM at
4761 * once is one less than the total number of descriptors that the buffer
4762 * can contain.
4763 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4764 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4765 * be provided at once.
4766 * Because of above requirement, one extra descriptor will be added to
4767 * make sure hardware always has one descriptor.
4768 */
4769 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4770 + sizeof(struct sps_iovec);
4771
4772 /*setup TX pipes */
4773 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4774 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4775
4776 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4777 ipa->desc_fifo_sz = desc_fifo_sz;
4778 ipa->priv = &hdd_ipa->iface_context[i];
4779 ipa->notify = hdd_ipa_i2w_cb;
4780
4781 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4782 ipa->ipa_ep_cfg.hdr.hdr_len =
4783 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4784 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4785 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4786 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4787 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4788 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4789 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4790 } else {
4791 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4792 }
4793 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4794
4795 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4796 ipa->keep_ipa_awake = 1;
4797
4798 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4799 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004800 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4801 "Failed for pipe %d ret: %d", i, ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004802 goto setup_sys_pipe_fail;
4803 }
4804 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4805 }
4806
4807 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4808 /*
4809 * Hard code it here, this can be extended if in case
4810 * PROD pipe is also per interface.
4811 * Right now there is no advantage of doing this.
4812 */
4813 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4814
4815 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4816
4817 ipa->client = hdd_ipa->prod_client;
4818
4819 ipa->desc_fifo_sz = desc_fifo_sz;
4820 ipa->priv = hdd_ipa;
4821 ipa->notify = hdd_ipa_w2i_cb;
4822
4823 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4824 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4825 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4826 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4827
4828 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4829 ipa->keep_ipa_awake = 1;
4830
4831 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4832 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304833 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004834 "Failed for RX pipe: %d", ret);
4835 goto setup_sys_pipe_fail;
4836 }
4837 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4838 }
4839
4840 return ret;
4841
4842setup_sys_pipe_fail:
4843
4844 while (--i >= 0) {
4845 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304846 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004847 sizeof(struct hdd_ipa_sys_pipe));
4848 }
4849
4850 return ret;
4851}
4852
4853/**
4854 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4855 * @hdd_ipa: Global HDD IPA context
4856 *
4857 * Return: None
4858 */
4859static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4860{
4861 int ret = 0, i;
4862 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4863 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4864 ret =
4865 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4866 conn_hdl);
4867 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304868 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004869 ret);
4870
4871 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4872 }
4873 }
4874}
4875
4876/**
4877 * hdd_ipa_register_interface() - register IPA interface
4878 * @hdd_ipa: Global IPA context
4879 * @iface_context: Per-interface IPA context
4880 *
4881 * Return: 0 on success, negative errno on error
4882 */
4883static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
4884 struct hdd_ipa_iface_context
4885 *iface_context)
4886{
4887 struct ipa_tx_intf tx_intf;
4888 struct ipa_rx_intf rx_intf;
4889 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
4890 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
4891 char *ifname = iface_context->adapter->dev->name;
4892
4893 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
4894 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
4895
4896 int num_prop = 1;
4897 int ret = 0;
4898
4899 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
4900 num_prop++;
4901
4902 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
4903 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304904 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004905 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304906 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004907 goto register_interface_fail;
4908 }
4909
4910 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
4911 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304912 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004913 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304914 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004915 goto register_interface_fail;
4916 }
4917
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304918 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
4919 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004920
4921 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4922 ifname, HDD_IPA_IPV4_NAME_EXT);
4923 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4924 ifname, HDD_IPA_IPV6_NAME_EXT);
4925
4926 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4927 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
4928 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4929 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4930
4931 /*
4932 * Interface ID is 3rd byte in the CLD header. Add the meta data and
4933 * mask to identify the interface in IPA hardware
4934 */
4935 rx_prop[IPA_IP_v4].attrib.meta_data =
4936 htonl(iface_context->adapter->sessionId << 16);
4937 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4938
4939 rx_intf.num_props++;
4940 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4941 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4942 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
4943 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4944 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4945 rx_prop[IPA_IP_v4].attrib.meta_data =
4946 htonl(iface_context->adapter->sessionId << 16);
4947 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4948
4949 rx_intf.num_props++;
4950 }
4951
4952 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4953 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4954 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4955 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
4956 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
4957 IPA_RESOURCE_NAME_MAX);
4958 tx_intf.num_props++;
4959
4960 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4961 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4962 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4963 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4964 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
4965 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
4966 IPA_RESOURCE_NAME_MAX);
4967 tx_intf.num_props++;
4968 }
4969
4970 tx_intf.prop = tx_prop;
4971 rx_intf.prop = rx_prop;
4972
4973 /* Call the ipa api to register interface */
4974 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
4975
4976register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304977 qdf_mem_free(tx_prop);
4978 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004979 return ret;
4980}
4981
4982/**
4983 * hdd_remove_ipa_header() - Remove a specific header from IPA
4984 * @name: Name of the header to be removed
4985 *
4986 * Return: None
4987 */
4988static void hdd_ipa_remove_header(char *name)
4989{
4990 struct ipa_ioc_get_hdr hdrlookup;
4991 int ret = 0, len;
4992 struct ipa_ioc_del_hdr *ipa_hdr;
4993
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304994 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004995 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
4996 ret = ipa_get_hdr(&hdrlookup);
4997 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004998 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999 name, ret);
5000 return;
5001 }
5002
Srinivas Girigowda97852372017-03-06 16:52:59 -08005003 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005004 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305005 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005006 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305007 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005008 return;
5009 }
5010 ipa_hdr->num_hdls = 1;
5011 ipa_hdr->commit = 0;
5012 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
5013 ipa_hdr->hdl[0].status = -1;
5014 ret = ipa_del_hdr(ipa_hdr);
5015 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305016 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005017 ret);
5018
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305019 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005020}
5021
5022/**
Yun Parkb187d542016-11-14 18:10:04 -08005023 * wlan_ipa_add_hdr() - Add IPA Tx header
5024 * @ipa_hdr: pointer to IPA header addition parameters
5025 *
5026 * Call IPA API to add IPA Tx header descriptor
5027 * and dump Tx header struct
5028 *
5029 * Return: 0 for success, non-zero for failure
5030 */
5031static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
5032{
5033 int ret;
5034
Srinivas Girigowda97852372017-03-06 16:52:59 -08005035 hdd_debug("==== IPA Tx Header ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08005036 "name: %s\n"
5037 "hdr_len: %d\n"
5038 "type: %d\n"
5039 "is_partial: %d\n"
5040 "hdr_hdl: 0x%x\n"
5041 "status: %d\n"
5042 "is_eth2_ofst_valid: %d\n"
5043 "eth2_ofst: %d\n",
5044 ipa_hdr->hdr[0].name,
5045 ipa_hdr->hdr[0].hdr_len,
5046 ipa_hdr->hdr[0].type,
5047 ipa_hdr->hdr[0].is_partial,
5048 ipa_hdr->hdr[0].hdr_hdl,
5049 ipa_hdr->hdr[0].status,
5050 ipa_hdr->hdr[0].is_eth2_ofst_valid,
5051 ipa_hdr->hdr[0].eth2_ofst);
5052
5053 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:",
5054 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
5055
5056 ret = ipa_add_hdr(ipa_hdr);
5057 return ret;
5058}
5059
5060/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005061 * hdd_ipa_add_header_info() - Add IPA header for a given interface
5062 * @hdd_ipa: Global HDD IPA context
5063 * @iface_context: Interface-specific HDD IPA context
5064 * @mac_addr: Interface MAC address
5065 *
5066 * Return: 0 on success, negativer errno value on error
5067 */
5068static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
5069 struct hdd_ipa_iface_context *iface_context,
5070 uint8_t *mac_addr)
5071{
5072 hdd_adapter_t *adapter = iface_context->adapter;
5073 char *ifname;
5074 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
5075 int ret = -EINVAL;
5076 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
5077 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
5078
5079 ifname = adapter->dev->name;
5080
Srinivas Girigowda97852372017-03-06 16:52:59 -08005081 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005082 ifname, mac_addr);
5083
5084 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305085 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005086 + sizeof(struct ipa_hdr_add));
5087 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305088 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005089 "%s: ipa_hdr allocation failed", ifname);
5090 ret = -ENOMEM;
5091 goto end;
5092 }
5093
5094 ipa_hdr->commit = 0;
5095 ipa_hdr->num_hdrs = 1;
5096
5097 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5098 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
5099 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
5100 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
5101 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305102 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005103 "ifname=%s, vdev_id=%d",
5104 ifname, uc_tx_hdr->ipa_hd.vdev_id);
5105 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5106 ifname, HDD_IPA_IPV4_NAME_EXT);
5107 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
5108 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
5109 ipa_hdr->hdr[0].is_partial = 1;
5110 ipa_hdr->hdr[0].hdr_hdl = 0;
5111 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
5112 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5113
Yun Parkb187d542016-11-14 18:10:04 -08005114 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005115 } else {
5116 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
5117
5118 /* Set the Source MAC */
5119 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
5120 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
5121
5122 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5123 ifname, HDD_IPA_IPV4_NAME_EXT);
5124 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
5125 ipa_hdr->hdr[0].is_partial = 1;
5126 ipa_hdr->hdr[0].hdr_hdl = 0;
5127 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
5128 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5129
5130 /* Set the type to IPV4 in the header */
5131 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
5132
5133 ret = ipa_add_hdr(ipa_hdr);
5134 }
5135 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305136 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005137 ifname, ret);
5138 goto end;
5139 }
5140
Srinivas Girigowda97852372017-03-06 16:52:59 -08005141 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005142 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
5143
5144 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5145 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5146 ifname, HDD_IPA_IPV6_NAME_EXT);
5147
5148 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5149 uc_tx_hdr =
5150 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
5151 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08005152 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005153 } else {
5154 /* Set the type to IPV6 in the header */
5155 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
5156 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08005157 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005158 }
5159
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005160 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305161 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005162 "%s: IPv6 add hdr failed: %d", ifname, ret);
5163 goto clean_ipv4_hdr;
5164 }
5165
Srinivas Girigowda97852372017-03-06 16:52:59 -08005166 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005167 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
5168 }
5169
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305170 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005171
5172 return ret;
5173
5174clean_ipv4_hdr:
5175 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5176 ifname, HDD_IPA_IPV4_NAME_EXT);
5177 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
5178end:
5179 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305180 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005181
5182 return ret;
5183}
5184
5185/**
5186 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
5187 * @adapter: Adapter upon which IPA was previously configured
5188 *
5189 * Return: None
5190 */
5191static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
5192{
5193 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5194 int ret;
5195 char name_ipa[IPA_RESOURCE_NAME_MAX];
5196
5197 /* Remove the headers */
5198 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
5199 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
5200 hdd_ipa_remove_header(name_ipa);
5201
5202 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5203 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
5204 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
5205 hdd_ipa_remove_header(name_ipa);
5206 }
5207 /* unregister the interface with IPA */
5208 ret = ipa_deregister_intf(adapter->dev->name);
5209 if (ret)
Srinivas Girigowda97852372017-03-06 16:52:59 -08005210 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005211 "%s: ipa_deregister_intf fail: %d",
5212 adapter->dev->name, ret);
5213}
5214
5215/**
5216 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
5217 * @iface_context: interface-specific IPA context
5218 *
5219 * Return: None
5220 */
5221static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
5222{
5223 if (iface_context == NULL)
5224 return;
5225
5226 hdd_ipa_clean_hdr(iface_context->adapter);
5227
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305228 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005229 iface_context->adapter->ipa_context = NULL;
5230 iface_context->adapter = NULL;
5231 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305232 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005233 iface_context->ifa_address = 0;
5234 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305235 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005236 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05305237 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005238 }
5239 iface_context->hdd_ipa->num_iface--;
5240}
5241
5242/**
5243 * hdd_ipa_setup_iface() - Setup IPA on a given interface
5244 * @hdd_ipa: HDD IPA global context
5245 * @adapter: Interface upon which IPA is being setup
5246 * @sta_id: Station ID of the API instance
5247 *
5248 * Return: 0 on success, negative errno value on error
5249 */
5250static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
5251 hdd_adapter_t *adapter, uint8_t sta_id)
5252{
5253 struct hdd_ipa_iface_context *iface_context = NULL;
5254 void *tl_context = NULL;
5255 int i, ret = 0;
5256
5257 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
5258 * channel change indication. Since these indications are sent by lower
5259 * layer as SAP updates and IPA doesn't have to do anything for these
5260 * updates so ignoring!
5261 */
Krunal Sonibe766b02016-03-10 13:00:44 -08005262 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005263 return 0;
5264
5265 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5266 if (hdd_ipa->iface_context[i].adapter == NULL) {
5267 iface_context = &(hdd_ipa->iface_context[i]);
5268 break;
5269 }
5270 }
5271
5272 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305273 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005274 "All the IPA interfaces are in use");
5275 ret = -ENOMEM;
5276 goto end;
5277 }
5278
5279 adapter->ipa_context = iface_context;
5280 iface_context->adapter = adapter;
5281 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08005282 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07005283 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005284 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305285 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005286 "Not able to get TL context sta_id: %d", sta_id);
5287 ret = -EINVAL;
5288 goto end;
5289 }
5290
5291 iface_context->tl_context = tl_context;
5292
5293 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
5294 adapter->dev->dev_addr);
5295
5296 if (ret)
5297 goto end;
5298
5299 /* Configure the TX and RX pipes filter rules */
5300 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
5301 if (ret)
5302 goto cleanup_header;
5303
5304 hdd_ipa->num_iface++;
5305 return ret;
5306
5307cleanup_header:
5308
5309 hdd_ipa_clean_hdr(adapter);
5310end:
5311 if (iface_context)
5312 hdd_ipa_cleanup_iface(iface_context);
5313 return ret;
5314}
5315
Yun Parka27049a2016-10-11 12:30:49 -07005316#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005317/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005318 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005319 * @mcc_mode: 0=MCC/1=SCC
5320 *
5321 * Return: 0 on success, negative errno value on error
5322 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005323static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005324{
5325 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305326 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005327 hdd_adapter_t *pAdapter;
5328 struct ipa_msg_meta meta;
5329 struct ipa_wlan_msg *msg;
5330 int ret;
5331
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005332 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005333 return -EINVAL;
5334
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005335 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
5336 return -EINVAL;
5337
5338 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005339 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005340 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305341 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005342 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08005343 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005344 pAdapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005345 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005346 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005347 hdd_deinit_tx_rx(pAdapter);
5348 }
5349 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005350 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005351 adapter_node = next;
5352 }
5353 }
5354
5355 /* Send SCC/MCC Switching event to IPA */
5356 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305357 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005358 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005359 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005360 return -ENOMEM;
5361 }
5362
5363 meta.msg_type = mcc_mode ?
5364 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Srinivas Girigowda97852372017-03-06 16:52:59 -08005365 hdd_debug("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005366
5367 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5368
5369 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005370 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005371 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305372 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005373 }
5374
5375 return ret;
5376}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005377
5378/**
5379 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5380 * @mcc_mode: 0=MCC/1=SCC
5381 *
5382 * Return: 0 on success, negative errno value on error
5383 */
5384int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
5385{
5386 int ret;
5387
5388 cds_ssr_protect(__func__);
5389 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5390 cds_ssr_unprotect(__func__);
5391
5392 return ret;
5393}
Yun Parka27049a2016-10-11 12:30:49 -07005394#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005395
5396/**
5397 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
5398 * @event: IPA WLAN event to be converted to a string
5399 *
5400 * Return: ASCII string representing the IPA WLAN event
5401 */
5402static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
5403{
5404 switch (event) {
5405 case WLAN_CLIENT_CONNECT:
5406 return "WLAN_CLIENT_CONNECT";
5407 case WLAN_CLIENT_DISCONNECT:
5408 return "WLAN_CLIENT_DISCONNECT";
5409 case WLAN_CLIENT_POWER_SAVE_MODE:
5410 return "WLAN_CLIENT_POWER_SAVE_MODE";
5411 case WLAN_CLIENT_NORMAL_MODE:
5412 return "WLAN_CLIENT_NORMAL_MODE";
5413 case SW_ROUTING_ENABLE:
5414 return "SW_ROUTING_ENABLE";
5415 case SW_ROUTING_DISABLE:
5416 return "SW_ROUTING_DISABLE";
5417 case WLAN_AP_CONNECT:
5418 return "WLAN_AP_CONNECT";
5419 case WLAN_AP_DISCONNECT:
5420 return "WLAN_AP_DISCONNECT";
5421 case WLAN_STA_CONNECT:
5422 return "WLAN_STA_CONNECT";
5423 case WLAN_STA_DISCONNECT:
5424 return "WLAN_STA_DISCONNECT";
5425 case WLAN_CLIENT_CONNECT_EX:
5426 return "WLAN_CLIENT_CONNECT_EX";
5427
5428 case IPA_WLAN_EVENT_MAX:
5429 default:
5430 return "UNKNOWN";
5431 }
5432}
5433
5434/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005435 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5436 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5437 *
5438 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
5439 */
5440static enum ipa_wlan_event
5441hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5442{
5443 enum ipa_wlan_event ipa_event;
5444
5445 switch (hdd_ipa_event_type) {
5446 case HDD_IPA_CLIENT_CONNECT:
5447 ipa_event = WLAN_CLIENT_CONNECT;
5448 break;
5449 case HDD_IPA_CLIENT_DISCONNECT:
5450 ipa_event = WLAN_CLIENT_DISCONNECT;
5451 break;
5452 case HDD_IPA_AP_CONNECT:
5453 ipa_event = WLAN_AP_CONNECT;
5454 break;
5455 case HDD_IPA_AP_DISCONNECT:
5456 ipa_event = WLAN_AP_DISCONNECT;
5457 break;
5458 case HDD_IPA_STA_CONNECT:
5459 ipa_event = WLAN_STA_CONNECT;
5460 break;
5461 case HDD_IPA_STA_DISCONNECT:
5462 ipa_event = WLAN_STA_DISCONNECT;
5463 break;
5464 case HDD_IPA_CLIENT_CONNECT_EX:
5465 ipa_event = WLAN_CLIENT_CONNECT_EX;
5466 break;
5467 case HDD_IPA_WLAN_EVENT_MAX:
5468 default:
5469 ipa_event = IPA_WLAN_EVENT_MAX;
5470 break;
5471 }
5472 return ipa_event;
5473
5474}
5475
5476/**
5477 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005478 * @adapter: adapter upon which the event was received
5479 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005480 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005481 * @mac_address: MAC address associated with the event
5482 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005483 * This function is meant to be called from within wlan_hdd_ipa.c
5484 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005485 * Return: 0 on success, negative errno value on error
5486 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07005487static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005488 enum ipa_wlan_event type, uint8_t *mac_addr)
5489{
5490 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5491 struct ipa_msg_meta meta;
5492 struct ipa_wlan_msg *msg;
5493 struct ipa_wlan_msg_ex *msg_ex = NULL;
5494 int ret;
5495
Srinivas Girigowda97852372017-03-06 16:52:59 -08005496 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005497 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5498 mac_addr, sta_id);
5499
5500 if (type >= IPA_WLAN_EVENT_MAX)
5501 return -EINVAL;
5502
5503 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5504 return -EINVAL;
5505
5506 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305507 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005508 return -EINVAL;
5509 }
5510
5511 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5512 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005513 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005514 return 0;
5515 }
5516
5517 /*
5518 * During IPA UC resource loading/unloading new events can be issued.
5519 * Store the events separately and handle them later.
5520 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005521 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5522 if (hdd_ipa->resource_loading) {
5523 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005524 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005525
Yun Park64c405e2017-01-10 22:35:51 -08005526 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5527 "IPA resource load in progress");
Yun Park7c4f31b2016-11-30 10:09:21 -08005528
Yun Park64c405e2017-01-10 22:35:51 -08005529 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005530
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005531 pending_event_count =
5532 qdf_list_size(&hdd_ipa->pending_event);
5533 if (pending_event_count >=
5534 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005535 hdd_debug("Reached max pending event count");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005536 qdf_list_remove_front(&hdd_ipa->pending_event,
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005537 (qdf_list_node_t **)&pending_event);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005538 } else {
5539 pending_event =
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005540 qdf_mem_malloc(sizeof(*pending_event));
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005541 }
5542
5543 if (!pending_event) {
Yun Park64c405e2017-01-10 22:35:51 -08005544 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park7c4f31b2016-11-30 10:09:21 -08005545 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5546 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005547 return -ENOMEM;
5548 }
5549
5550 pending_event->adapter = adapter;
5551 pending_event->sta_id = sta_id;
5552 pending_event->type = type;
5553 qdf_mem_copy(pending_event->mac_addr,
5554 mac_addr,
5555 QDF_MAC_ADDR_SIZE);
5556 qdf_list_insert_back(&hdd_ipa->pending_event,
5557 &pending_event->node);
5558
Yun Park64c405e2017-01-10 22:35:51 -08005559 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005560 return 0;
5561 } else if (hdd_ipa->resource_unloading) {
Yun Park64c405e2017-01-10 22:35:51 -08005562 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5563 "IPA resource unload in progress");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005564 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005565 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005566 }
5567
5568 hdd_ipa->stats.event[type]++;
5569
Leo Chang3bc8fed2015-11-13 10:59:47 -08005570 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005571 switch (type) {
5572 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005573 qdf_mutex_acquire(&hdd_ipa->event_lock);
5574
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005575 /* STA already connected and without disconnect, connect again
5576 * This is Roaming scenario
5577 */
5578 if (hdd_ipa->sta_connected)
5579 hdd_ipa_cleanup_iface(adapter->ipa_context);
5580
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005581 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5582 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305583 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005584 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005585 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005586
Yun Park8f289c82016-10-18 16:38:21 -07005587 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5588 (hdd_ipa->sap_num_connected_sta > 0) &&
5589 !hdd_ipa->sta_connected) {
5590 qdf_mutex_release(&hdd_ipa->event_lock);
5591 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005592 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005593 qdf_mutex_acquire(&hdd_ipa->event_lock);
5594 }
5595
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005596 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005597 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005598 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005599
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005600 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005601
5602 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005603 break;
5604
5605 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005606 qdf_mutex_acquire(&hdd_ipa->event_lock);
5607
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005608 /* For DFS channel we get two start_bss event (before and after
5609 * CAC). Also when ACS range includes both DFS and non DFS
5610 * channels, we could possibly change channel many times due to
5611 * RADAR detection and chosen channel may not be a DFS channels.
5612 * So dont return error here. Just discard the event.
5613 */
Yun Park8f289c82016-10-18 16:38:21 -07005614 if (adapter->ipa_context) {
5615 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005616 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005617 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005618
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005619 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5620 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005621 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005622 hdd_err("%s: Evt: %d, Interface setup failed",
5623 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005624 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005625 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005626
Yun Park8f289c82016-10-18 16:38:21 -07005627 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5628 qdf_mutex_release(&hdd_ipa->event_lock);
5629 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005630 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005631 qdf_mutex_acquire(&hdd_ipa->event_lock);
5632 }
5633
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005634 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005635 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005636 (adapter->ipa_context))->iface_id;
5637
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305638 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005639 break;
5640
5641 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305642 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005643
5644 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005645 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005646 hdd_err("%s: Evt: %d, STA already disconnected",
5647 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005648 return -EINVAL;
5649 }
Yun Parka37592b2016-06-11 17:10:28 -07005650
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005651 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005652
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005653 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005654 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005655 msg_ex->name);
5656 } else {
5657 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005658 if (!hdd_ipa->num_iface &&
5659 (HDD_IPA_UC_NUM_WDI_PIPE ==
5660 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005661 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005662 }
5663
Yun Park74127cf2016-09-18 11:22:41 -07005664 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5665 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005666 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005667 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005668 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005669 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005670 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5671 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005672 }
5673
Yun Park8f289c82016-10-18 16:38:21 -07005674 hdd_ipa_cleanup_iface(adapter->ipa_context);
5675
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305676 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005677 break;
5678
5679 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005680 qdf_mutex_acquire(&hdd_ipa->event_lock);
5681
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005682 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005683 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005684 hdd_err("%s: Evt: %d, SAP already disconnected",
5685 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005686 return -EINVAL;
5687 }
5688
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005689 if ((!hdd_ipa->num_iface) &&
5690 (HDD_IPA_UC_NUM_WDI_PIPE ==
5691 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005692 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005693 /*
5694 * We disable WDI pipes directly here since
5695 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5696 * processed when unloading WLAN driver is in
5697 * progress
5698 */
5699 hdd_ipa_uc_disable_pipes(hdd_ipa);
5700 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305701 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005702 "NO INTF left but still pipe clean up");
5703 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5704 }
5705 }
5706
5707 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005708 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005709 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005710 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005711 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005712 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5713 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005714 }
Yun Parka37592b2016-06-11 17:10:28 -07005715
Yun Park8f289c82016-10-18 16:38:21 -07005716 hdd_ipa_cleanup_iface(adapter->ipa_context);
5717
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305718 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005719 break;
5720
5721 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005722 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005723 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005724 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305725 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005726 return 0;
5727 }
5728
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305729 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005730 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5731 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005732 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305733 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005734 "%s: STA ID %d found, not valid",
5735 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005736 return 0;
5737 }
Yun Park312f71a2015-12-08 10:22:42 -08005738
5739 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005740 if (hdd_ipa->sap_num_connected_sta == 0 &&
5741 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005742 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005743 hdd_ipa->sta_connected) {
5744 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005745 hdd_ipa_uc_offload_enable_disable(
5746 hdd_get_adapter(hdd_ipa->hdd_ctx,
5747 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005748 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005749 qdf_mutex_acquire(&hdd_ipa->event_lock);
5750 }
Yun Parka37592b2016-06-11 17:10:28 -07005751
Yun Park312f71a2015-12-08 10:22:42 -08005752 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5753 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305754 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005755 "%s: handle 1st con ret %d",
5756 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005757
5758 if (hdd_ipa_uc_sta_is_enabled(
5759 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005760 hdd_ipa->sta_connected) {
5761 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005762 hdd_ipa_uc_offload_enable_disable(
5763 hdd_get_adapter(
5764 hdd_ipa->hdd_ctx,
5765 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005766 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005767 } else {
5768 qdf_mutex_release(&hdd_ipa->event_lock);
5769 }
Yun Parka37592b2016-06-11 17:10:28 -07005770
Yun Park312f71a2015-12-08 10:22:42 -08005771 return ret;
5772 }
5773 }
5774
5775 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005776
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305777 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005778
5779 meta.msg_type = type;
5780 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5781 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305782 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005783
5784 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305785 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005786 "msg_ex allocation failed");
5787 return -ENOMEM;
5788 }
5789 strlcpy(msg_ex->name, adapter->dev->name,
5790 IPA_RESOURCE_NAME_MAX);
5791 msg_ex->num_of_attribs = 1;
5792 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5793 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5794 msg_ex->attribs[0].offset =
5795 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5796 } else {
5797 msg_ex->attribs[0].offset =
5798 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5799 }
5800 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5801 IPA_MAC_ADDR_SIZE);
5802
5803 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5804
5805 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005806 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305807 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305808 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005809 return ret;
5810 }
5811 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005812 return ret;
5813
5814 case WLAN_CLIENT_DISCONNECT:
5815 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005816 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005817 "%s: IPA UC OFFLOAD NOT ENABLED",
5818 msg_ex->name);
5819 return 0;
5820 }
5821
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305822 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005823 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005824 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305825 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005826 "%s: STA ID %d NOT found, not valid",
5827 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005828 return 0;
5829 }
5830 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005831
Yun Park9b5030f2016-11-08 12:02:37 -08005832 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005833 if (!hdd_ipa->sap_num_connected_sta &&
5834 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005835 if ((false == hdd_ipa->resource_unloading)
5836 && (HDD_IPA_UC_NUM_WDI_PIPE ==
5837 hdd_ipa->activated_fw_pipe)) {
5838 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5839 }
5840
Yun Park8f289c82016-10-18 16:38:21 -07005841 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005842
5843 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5844 hdd_ipa->sta_connected)
5845 hdd_ipa_uc_offload_enable_disable(
5846 hdd_get_adapter(hdd_ipa->hdd_ctx,
5847 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005848 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005849 } else {
5850 qdf_mutex_release(&hdd_ipa->event_lock);
5851 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005852 break;
5853
5854 default:
5855 return 0;
5856 }
5857
5858 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305859 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005860 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305861 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005862 return -ENOMEM;
5863 }
5864
5865 meta.msg_type = type;
5866 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5867 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5868
Srinivas Girigowda97852372017-03-06 16:52:59 -08005869 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005870 msg->name, meta.msg_type);
5871
5872 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5873
5874 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005875 hdd_err("%s: Evt: %d fail:%d",
5876 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305877 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005878 return ret;
5879 }
5880
5881 hdd_ipa->stats.num_send_msg++;
5882
5883end:
5884 return ret;
5885}
5886
5887/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005888 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005889 * @adapter: adapter upon which the event was received
5890 * @sta_id: station id for the event
5891 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5892 * @mac_address: MAC address associated with the event
5893 *
5894 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5895 *
5896 * Return: 0 on success, negative errno value on error
5897 */
5898int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
5899 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5900{
5901 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005902 int ret = 0;
5903
5904 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005905
Leo Changa202b522016-10-14 16:13:50 -07005906 /* Data path offload only support for STA and SAP mode */
5907 if ((QDF_STA_MODE == adapter->device_mode) ||
5908 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005909 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005910
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005911 cds_ssr_unprotect(__func__);
5912
5913 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005914}
5915
5916/**
5917 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5918 * @hdd_ipa: Global HDD IPA context
5919 *
5920 * Return: None
5921 */
5922static void
5923hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5924{
5925 unsigned int pending_event_count;
5926 struct ipa_uc_pending_event *pending_event = NULL;
5927
5928 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005929 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005930 "%s, Pending Event Count %d", __func__, pending_event_count);
5931 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005932 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005933 "%s, No Pending Event", __func__);
5934 return;
5935 }
5936
5937 qdf_list_remove_front(&hdd_ipa->pending_event,
5938 (qdf_list_node_t **)&pending_event);
5939 while (pending_event != NULL) {
5940 __hdd_ipa_wlan_evt(pending_event->adapter,
5941 pending_event->type,
5942 pending_event->sta_id,
5943 pending_event->mac_addr);
5944 qdf_mem_free(pending_event);
5945 pending_event = NULL;
5946 qdf_list_remove_front(&hdd_ipa->pending_event,
5947 (qdf_list_node_t **)&pending_event);
5948 }
5949}
5950
5951/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005952 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5953 * @state: IPA RM state value
5954 *
5955 * Return: ASCII string representing the IPA RM state
5956 */
5957static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5958{
5959 switch (state) {
5960 case HDD_IPA_RM_RELEASED:
5961 return "RELEASED";
5962 case HDD_IPA_RM_GRANT_PENDING:
5963 return "GRANT_PENDING";
5964 case HDD_IPA_RM_GRANTED:
5965 return "GRANTED";
5966 }
5967
5968 return "UNKNOWN";
5969}
5970
5971/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005972 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005973 * @hdd_ctx: HDD global context
5974 *
5975 * Allocate hdd_ipa resources, ipa pipe resource and register
5976 * wlan interface with IPA module.
5977 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305978 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005979 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005980static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005981{
5982 struct hdd_ipa_priv *hdd_ipa = NULL;
5983 int ret, i;
5984 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005985 struct ol_txrx_pdev_t *pdev = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005986
5987 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305988 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005989
Yun Parkbaa62862017-01-18 13:43:34 -08005990 ENTER();
5991
5992 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005993 if (!pdev) {
5994 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5995 goto fail_return;
5996 }
5997
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305998 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005999 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306000 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08006001 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006002 }
6003
6004 hdd_ctx->hdd_ipa = hdd_ipa;
6005 ghdd_ipa = hdd_ipa;
6006 hdd_ipa->hdd_ctx = hdd_ctx;
6007 hdd_ipa->num_iface = 0;
6008
6009 /* Create the interface context */
6010 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6011 iface_context = &hdd_ipa->iface_context[i];
6012 iface_context->hdd_ipa = hdd_ipa;
6013 iface_context->cons_client =
6014 hdd_ipa_adapter_2_client[i].cons_client;
6015 iface_context->prod_client =
6016 hdd_ipa_adapter_2_client[i].prod_client;
6017 iface_context->iface_id = i;
6018 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306019 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08006020 }
6021 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08006022 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
6023 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006024 }
6025
Leo Chang69c39692016-10-12 20:11:12 -07006026 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306027 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05306028 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006029
6030 ret = hdd_ipa_setup_rm(hdd_ipa);
6031 if (ret)
6032 goto fail_setup_rm;
6033
6034 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
6035 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306036 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006037 hdd_ipa->sap_num_connected_sta = 0;
6038 hdd_ipa->ipa_tx_packets_diff = 0;
6039 hdd_ipa->ipa_rx_packets_diff = 0;
6040 hdd_ipa->ipa_p_tx_packets = 0;
6041 hdd_ipa->ipa_p_rx_packets = 0;
6042 hdd_ipa->resource_loading = false;
6043 hdd_ipa->resource_unloading = false;
6044 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07006045 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08006046 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006047 /* Setup IPA sys_pipe for MCC */
6048 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
6049 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6050 if (ret)
6051 goto fail_create_sys_pipe;
6052 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08006053 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
6054 goto fail_create_sys_pipe;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006055 } else {
6056 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6057 if (ret)
6058 goto fail_create_sys_pipe;
6059 }
6060
Yun Parkbaa62862017-01-18 13:43:34 -08006061 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306062 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006063
6064fail_create_sys_pipe:
6065 hdd_ipa_destroy_rm_resource(hdd_ipa);
6066fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306067 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306068 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08006069 hdd_ctx->hdd_ipa = NULL;
6070 ghdd_ipa = NULL;
6071fail_return:
Yun Parkbaa62862017-01-18 13:43:34 -08006072 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306073 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006074}
6075
6076/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006077 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
6078 * @hdd_ctx: HDD global context
6079 *
6080 * Allocate hdd_ipa resources, ipa pipe resource and register
6081 * wlan interface with IPA module.
6082 *
6083 * Return: QDF_STATUS enumeration
6084 */
6085QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
6086{
6087 QDF_STATUS ret;
6088
6089 cds_ssr_protect(__func__);
6090 ret = __hdd_ipa_init(hdd_ctx);
6091 cds_ssr_unprotect(__func__);
6092
6093 return ret;
6094}
6095
Arun Khandavallicc544b32017-01-30 19:52:16 +05306096
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006097/**
Yun Parkf19e07d2015-11-20 11:34:27 -08006098 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
6099 * @hdd_ipa: pointer to HDD IPA struct
6100 *
6101 * Return: none
6102 */
Jeff Johnsond7720632016-10-05 16:04:32 -07006103static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08006104{
6105 struct ipa_uc_pending_event *pending_event = NULL;
6106
Anurag Chouhanffb21542016-02-17 14:33:03 +05306107 while (qdf_list_remove_front(&hdd_ipa->pending_event,
6108 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306109 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08006110 }
6111
Anurag Chouhanffb21542016-02-17 14:33:03 +05306112 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08006113}
6114
6115/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006116 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006117 * @hdd_ctx: HDD global context
6118 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306119 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006120 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006121static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006122{
6123 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
6124 int i;
6125 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05306126 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006127 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
6128
6129 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306130 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006131
6132 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
6133 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
6134 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6135 }
6136
6137 /* Teardown IPA sys_pipe for MCC */
6138 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
6139 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6140
6141 hdd_ipa_destroy_rm_resource(hdd_ipa);
6142
6143#ifdef WLAN_OPEN_SOURCE
6144 cancel_work_sync(&hdd_ipa->pm_work);
6145#endif
6146
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306147 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006148
Nirav Shahcbc6d722016-03-01 16:24:53 +05306149 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
6150 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306151 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006152
6153 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
6154 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
6155
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306156 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006157 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306158 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006159
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306160 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006161
6162 /* destory the interface lock */
6163 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6164 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306165 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006166 }
6167
6168 /* This should never hit but still make sure that there are no pending
6169 * descriptor in IPA hardware
6170 */
6171 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306172 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006173 "IPA Pending write done: %d Waiting!",
6174 hdd_ipa->pending_hw_desc_cnt);
6175
6176 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
6177 usleep_range(100, 100);
6178 }
6179
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306180 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006181 "IPA Pending write done: desc: %d %s(%d)!",
6182 hdd_ipa->pending_hw_desc_cnt,
6183 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
6184 : "leak", i);
6185 }
6186 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08006187 if (ipa_uc_dereg_rdyCB())
6188 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
6189 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006190 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08006191 if (true == hdd_ipa->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08006192 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Govind Singh0487bf22016-08-24 23:08:57 +05306193 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
6194 __func__, hdd_ipa->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08006195 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
Srinivas Girigowda97852372017-03-06 16:52:59 -08006196 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Govind Singh0487bf22016-08-24 23:08:57 +05306197 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
6198 __func__, hdd_ipa->rx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08006199 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
6200 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306201 qdf_mutex_destroy(&hdd_ipa->event_lock);
6202 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08006203 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006204
6205#ifdef WLAN_OPEN_SOURCE
6206 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6207 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
6208 hdd_ipa->uc_op_work[i].msg = NULL;
6209 }
6210#endif
6211 }
6212
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306213 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006214 hdd_ctx->hdd_ipa = NULL;
6215
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306216 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006217}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006218
6219/**
6220 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
6221 * @hdd_ctx: HDD global context
6222 *
6223 * Return: QDF_STATUS enumeration
6224 */
6225QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
6226{
6227 QDF_STATUS ret;
6228
6229 cds_ssr_protect(__func__);
6230 ret = __hdd_ipa_cleanup(hdd_ctx);
6231 cds_ssr_unprotect(__func__);
6232
6233 return ret;
6234}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006235#endif /* IPA_OFFLOAD */