blob: 902fbc34360c58bf4594a1e83f4d79df5be54365 [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,
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800100 HDD_IPA_UC_OPCODE_UC_READY = 8,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800101 /* keep this last */
102 HDD_IPA_UC_OPCODE_MAX
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700103};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800104
105/**
106 * enum - Reason codes for stat query
107 *
108 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
109 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
110 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800111 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800112 */
113enum {
114 HDD_IPA_UC_STAT_REASON_NONE,
115 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -0800116 HDD_IPA_UC_STAT_REASON_BW_CAL,
117 HDD_IPA_UC_STAT_REASON_DUMP_INFO
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800118};
119
120/**
121 * enum hdd_ipa_rm_state - IPA resource manager state
122 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
123 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
124 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
125 */
126enum hdd_ipa_rm_state {
127 HDD_IPA_RM_RELEASED,
128 HDD_IPA_RM_GRANT_PENDING,
129 HDD_IPA_RM_GRANTED,
130};
131
132struct llc_snap_hdr {
133 uint8_t dsap;
134 uint8_t ssap;
135 uint8_t resv[4];
136 __be16 eth_type;
137} __packed;
138
Leo Chang3bc8fed2015-11-13 10:59:47 -0800139/**
140 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
141 * @eth: ether II header
142 * @llc_snap: LLC snap header
143 *
144 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800145struct hdd_ipa_tx_hdr {
146 struct ethhdr eth;
147 struct llc_snap_hdr llc_snap;
148} __packed;
149
Leo Chang3bc8fed2015-11-13 10:59:47 -0800150/**
151 * struct frag_header - fragment header type registered to IPA hardware
152 * @length: fragment length
153 * @reserved1: Reserved not used
154 * @reserved2: Reserved not used
155 *
156 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800157struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800158 uint16_t length;
159 uint32_t reserved1;
160 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800161} __packed;
162
Leo Chang3bc8fed2015-11-13 10:59:47 -0800163/**
164 * struct ipa_header - ipa header type registered to IPA hardware
165 * @vdev_id: vdev id
166 * @reserved: Reserved not used
167 *
168 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800169struct ipa_header {
170 uint32_t
171 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
172 reserved:24;
173} __packed;
174
Leo Chang3bc8fed2015-11-13 10:59:47 -0800175/**
176 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
177 * @frag_hd: fragment header
178 * @ipa_hd: ipa header
179 * @eth: ether II header
180 *
181 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800182struct hdd_ipa_uc_tx_hdr {
183 struct frag_header frag_hd;
184 struct ipa_header ipa_hd;
185 struct ethhdr eth;
186} __packed;
187
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800188/**
189 * struct hdd_ipa_cld_hdr - IPA CLD Header
190 * @reserved: reserved fields
191 * @iface_id: interface ID
192 * @sta_id: Station ID
193 *
194 * Packed 32-bit structure
195 * +----------+----------+--------------+--------+
196 * | Reserved | QCMAP ID | interface id | STA ID |
197 * +----------+----------+--------------+--------+
198 */
199struct hdd_ipa_cld_hdr {
200 uint8_t reserved[2];
201 uint8_t iface_id;
202 uint8_t sta_id;
203} __packed;
204
205struct hdd_ipa_rx_hdr {
206 struct hdd_ipa_cld_hdr cld_hdr;
207 struct ethhdr eth;
208} __packed;
209
210struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700211 bool exception;
212 hdd_adapter_t *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800213 struct hdd_ipa_iface_context *iface_context;
214 struct ipa_rx_data *ipa_tx_desc;
215};
216
217struct hdd_ipa_uc_rx_hdr {
218 struct ethhdr eth;
219} __packed;
220
221struct hdd_ipa_sys_pipe {
222 uint32_t conn_hdl;
223 uint8_t conn_hdl_valid;
224 struct ipa_sys_connect_params ipa_sys_params;
225};
226
227struct hdd_ipa_iface_stats {
228 uint64_t num_tx;
229 uint64_t num_tx_drop;
230 uint64_t num_tx_err;
231 uint64_t num_tx_cac_drop;
232 uint64_t num_rx_prefilter;
233 uint64_t num_rx_ipa_excep;
234 uint64_t num_rx_recv;
235 uint64_t num_rx_recv_mul;
236 uint64_t num_rx_send_desc_err;
237 uint64_t max_rx_mul;
238};
239
240struct hdd_ipa_priv;
241
242struct hdd_ipa_iface_context {
243 struct hdd_ipa_priv *hdd_ipa;
244 hdd_adapter_t *adapter;
245 void *tl_context;
246
247 enum ipa_client_type cons_client;
248 enum ipa_client_type prod_client;
249
250 uint8_t iface_id; /* This iface ID */
251 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530252 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800253 uint32_t ifa_address;
254 struct hdd_ipa_iface_stats stats;
255};
256
257struct hdd_ipa_stats {
258 uint32_t event[IPA_WLAN_EVENT_MAX];
259 uint64_t num_send_msg;
260 uint64_t num_free_msg;
261
262 uint64_t num_rm_grant;
263 uint64_t num_rm_release;
264 uint64_t num_rm_grant_imm;
265 uint64_t num_cons_perf_req;
266 uint64_t num_prod_perf_req;
267
268 uint64_t num_rx_drop;
269 uint64_t num_rx_ipa_tx_dp;
270 uint64_t num_rx_ipa_splice;
271 uint64_t num_rx_ipa_loop;
272 uint64_t num_rx_ipa_tx_dp_err;
273 uint64_t num_rx_ipa_write_done;
274 uint64_t num_max_ipa_tx_mul;
275 uint64_t num_rx_ipa_hw_maxed_out;
276 uint64_t max_pend_q_cnt;
277
278 uint64_t num_tx_comp_cnt;
279 uint64_t num_tx_queued;
280 uint64_t num_tx_dequeued;
281 uint64_t num_max_pm_queue;
282
283 uint64_t num_freeq_empty;
284 uint64_t num_pri_freeq_empty;
285 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800286 uint64_t num_tx_fwd_ok;
287 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800288};
289
290struct ipa_uc_stas_map {
291 bool is_reserved;
292 uint8_t sta_id;
293};
294struct op_msg_type {
295 uint8_t msg_t;
296 uint8_t rsvd;
297 uint16_t op_code;
298 uint16_t len;
299 uint16_t rsvd_snd;
300};
301
302struct ipa_uc_fw_stats {
303 uint32_t tx_comp_ring_base;
304 uint32_t tx_comp_ring_size;
305 uint32_t tx_comp_ring_dbell_addr;
306 uint32_t tx_comp_ring_dbell_ind_val;
307 uint32_t tx_comp_ring_dbell_cached_val;
308 uint32_t tx_pkts_enqueued;
309 uint32_t tx_pkts_completed;
310 uint32_t tx_is_suspend;
311 uint32_t tx_reserved;
312 uint32_t rx_ind_ring_base;
313 uint32_t rx_ind_ring_size;
314 uint32_t rx_ind_ring_dbell_addr;
315 uint32_t rx_ind_ring_dbell_ind_val;
316 uint32_t rx_ind_ring_dbell_ind_cached_val;
317 uint32_t rx_ind_ring_rdidx_addr;
318 uint32_t rx_ind_ring_rd_idx_cached_val;
319 uint32_t rx_refill_idx;
320 uint32_t rx_num_pkts_indicated;
321 uint32_t rx_buf_refilled;
322 uint32_t rx_num_ind_drop_no_space;
323 uint32_t rx_num_ind_drop_no_buf;
324 uint32_t rx_is_suspend;
325 uint32_t rx_reserved;
326};
327
328struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530329 qdf_list_node_t node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800330 hdd_adapter_t *adapter;
331 enum ipa_wlan_event type;
332 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530333 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800334};
335
336/**
337 * struct uc_rm_work_struct
338 * @work: uC RM work
339 * @event: IPA RM event
340 */
341struct uc_rm_work_struct {
342 struct work_struct work;
343 enum ipa_rm_event event;
344};
345
346/**
347 * struct uc_op_work_struct
348 * @work: uC OP work
349 * @msg: OP message
350 */
351struct uc_op_work_struct {
352 struct work_struct work;
353 struct op_msg_type *msg;
354};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800355
356/**
357 * struct uc_rt_debug_info
358 * @time: system time
359 * @ipa_excep_count: IPA exception packet count
360 * @rx_drop_count: IPA Rx drop packet count
361 * @net_sent_count: IPA Rx packet sent to network stack count
362 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800363 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800364 * @tx_fwd_count: IPA Tx forward packet count
365 * @rx_destructor_call: IPA Rx packet destructor count
366 */
367struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530368 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800369 uint64_t ipa_excep_count;
370 uint64_t rx_drop_count;
371 uint64_t net_sent_count;
372 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800373 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800374 uint64_t tx_fwd_count;
375 uint64_t rx_destructor_call;
376};
377
378struct hdd_ipa_priv {
379 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
380 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
381 uint8_t num_iface;
382 enum hdd_ipa_rm_state rm_state;
383 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530384 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800385 * APIs as it is taken care gracefully. Without this, kernel would throw
386 * an warning if spin_lock_bh is used while IRQ is disabled
387 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530388 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800389 struct uc_rm_work_struct uc_rm_work;
390 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530391 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800392 struct delayed_work wake_lock_work;
393 bool wake_lock_released;
394
395 enum ipa_client_type prod_client;
396
397 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530398 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800399 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530400 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800401 bool suspended;
402
403 uint32_t pending_hw_desc_cnt;
404 uint32_t hw_desc_cnt;
405 spinlock_t q_lock;
406 uint32_t freeq_cnt;
407 struct list_head free_desc_head;
408
409 uint32_t pend_q_cnt;
410 struct list_head pend_desc_head;
411
412 hdd_context_t *hdd_ctx;
413
414 struct dentry *debugfs_dir;
415 struct hdd_ipa_stats stats;
416
417 struct notifier_block ipv4_notifier;
418 uint32_t curr_prod_bw;
419 uint32_t curr_cons_bw;
420
421 uint8_t activated_fw_pipe;
422 uint8_t sap_num_connected_sta;
423 uint8_t sta_connected;
424 uint32_t tx_pipe_handle;
425 uint32_t rx_pipe_handle;
426 bool resource_loading;
427 bool resource_unloading;
428 bool pending_cons_req;
429 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530430 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530431 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700432 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800433 uint32_t ipa_tx_packets_diff;
434 uint32_t ipa_rx_packets_diff;
435 uint32_t ipa_p_tx_packets;
436 uint32_t ipa_p_rx_packets;
437 uint32_t stat_req_reason;
438 uint64_t ipa_tx_forward;
439 uint64_t ipa_rx_discard;
440 uint64_t ipa_rx_net_send_count;
441 uint64_t ipa_rx_internel_drop_count;
442 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530443 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800444 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
445 unsigned int rt_buf_fill_index;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800446 struct ipa_wdi_in_params cons_pipe_in;
447 struct ipa_wdi_in_params prod_pipe_in;
448 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800449 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530450 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530451 qdf_mutex_t rt_debug_lock;
452 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800453 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800454 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530455 qdf_dma_addr_t tx_comp_doorbell_paddr;
456 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800457
458 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
459 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800460};
461
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800462/**
Houston Hoffman23e76f92016-02-26 12:19:11 -0800463 * FIXME: The following conversion routines are just stubs.
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800464 * They will be implemented fully by another update.
465 * The stubs will let the compile go ahead, and functionality
466 * is broken.
467 * This should be OK and IPA is not enabled yet
468 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700469static void *wlan_hdd_stub_priv_to_addr(uint32_t priv)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800470{
471 void *vaddr;
472 uint32_t ipa_priv = priv;
473
474 vaddr = &ipa_priv; /* just to use the var */
475 vaddr = NULL;
476 return vaddr;
477}
478
Jeff Johnsond7720632016-10-05 16:04:32 -0700479static uint32_t wlan_hdd_stub_addr_to_priv(void *ptr)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800480{
481 uint32_t ipa_priv = 0;
482
483 BUG_ON(ptr == NULL);
484 return ipa_priv;
485}
Leo Changcc923e22016-06-16 15:29:03 -0700486
487#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
488#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800489#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
490#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
491#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
492#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
493#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
494#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700495#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
496 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800497
498#define HDD_IPA_GET_IFACE_ID(_data) \
499 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
500
501#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530502 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800503 "%s:%d: "fmt, __func__, __LINE__, ## args)
504
Govind Singhb6a89772016-08-12 11:23:35 +0530505#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
506 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
507 "%s:%d: "fmt, __func__, __LINE__, ## args)
508
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800509#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
510 do { \
Yun Parkec845302016-12-15 09:22:57 -0800511 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \
512 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800513 } while (0)
514
515#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
516 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
517
518#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
519 do { \
520 hdd_ipa->ipa_rx_internel_drop_count++; \
521 } while (0)
522#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
523 do { \
524 hdd_ipa->ipa_rx_net_send_count++; \
525 } while (0)
526#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
527
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700528#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800529#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
530do { \
531 pipe_in.u.ul.rdy_ring_rp_va = \
532 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
533 pipe_in.u.ul.rdy_comp_ring_base_pa = \
534 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
535 pipe_in.u.ul.rdy_comp_ring_size = \
536 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
537 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
538 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
539 pipe_in.u.ul.rdy_comp_ring_wp_va = \
540 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800541} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700542
543#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800544#else
545/* Do nothing */
546#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
Leo Chang63d73612016-10-18 18:09:43 -0700547#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700548#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800549
Yun Parkb187d542016-11-14 18:10:04 -0800550#define HDD_IPA_DBG_DUMP_RX_LEN 32
551#define HDD_IPA_DBG_DUMP_TX_LEN 48
552
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800553static struct hdd_ipa_adapter_2_client {
554 enum ipa_client_type cons_client;
555 enum ipa_client_type prod_client;
556} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
557 {
558 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
559 }, {
560 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
561 }, {
562 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
563 },
564};
565
566/* For Tx pipes, use Ethernet-II Header format */
567struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
568 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800569 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800570 0x00000000,
571 0x00000000
572 },
573 {
574 0x00000000
575 },
576 {
577 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
578 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
579 0x0008
580 }
581};
582
583/* For Tx pipes, use 802.3 Header format */
584static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
585 {
586 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
587 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
588 0x00 /* length can be zero */
589 },
590 {
591 /* LLC SNAP header 8 bytes */
592 0xaa, 0xaa,
593 {0x03, 0x00, 0x00, 0x00},
594 0x0008 /* type value(2 bytes) ,filled by wlan */
595 /* 0x0800 - IPV4, 0x86dd - IPV6 */
596 }
597};
598
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800599static struct hdd_ipa_priv *ghdd_ipa;
600
601/* Local Function Prototypes */
602static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
603 unsigned long data);
604static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
605 unsigned long data);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800606static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800607
608static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700609static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800610
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800611#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
612 defined(IPA_CLIENT_IS_MHI_CONS))
613/**
614 * hdd_ipa_uc_get_db_paddr() - Get Doorbell physical address
615 * @db_paddr: Doorbell physical address should be given bu IPA
616 * @client: IPA client type
617 *
618 * Query doorbell physical address from IPA
619 * IPA will give physical address for TX COMP and RX READY
620 *
621 * Return: None
622 */
623static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
624 enum ipa_client_type client)
625{
626 struct ipa_wdi_db_params dbpa;
627
628 dbpa.client = client;
629 ipa_uc_wdi_get_dbpa(&dbpa);
630 *db_paddr = dbpa.uc_door_bell_pa;
Srinivas Girigowda97852372017-03-06 16:52:59 -0800631 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s PROD DB get dbpa 0x%x",
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800632 __func__, (unsigned int)dbpa.uc_door_bell_pa);
633}
634
635/**
636 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
637 * @priv_ctxt: hdd ipa local context
638 *
639 * Will be called by IPA context.
640 * It's atomic context, then should be scheduled to kworker thread
641 *
642 * Return: None
643 */
644static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
645{
646 struct hdd_ipa_priv *hdd_ipa;
647 struct op_msg_type *msg;
648 struct uc_op_work_struct *uc_op_work;
649
650 if (priv_ctxt == NULL) {
651 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
652 return;
653 }
654
655 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
656 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
657 if (!msg) {
658 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
659 return;
660 }
661
662 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
663
664 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
665
666 /* When the same uC OPCODE is already pended, just return */
667 if (uc_op_work->msg)
668 return;
669
670 uc_op_work->msg = msg;
671 schedule_work(&uc_op_work->work);
672}
673
674/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800675 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
676 * @ctrl: WDI control value
677 *
678 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
679 *
680 * Return: 0 on message send to ipa, -1 on failure
681 */
682static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
683{
684 struct ipa_msg_meta meta;
685 struct ipa_wlan_msg *ipa_msg;
686 int ret = 0;
687
688 /* WDI enable message to IPA */
689 meta.msg_len = sizeof(*ipa_msg);
690 ipa_msg = qdf_mem_malloc(meta.msg_len);
691 if (ipa_msg == NULL) {
692 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
693 "msg allocation failed");
694 return -ENOMEM;
695 }
696
697 if (ctrl == true)
698 meta.msg_type = WLAN_WDI_ENABLE;
699 else
700 meta.msg_type = WLAN_WDI_DISABLE;
701
Srinivas Girigowda97852372017-03-06 16:52:59 -0800702 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800703 "ipa_send_msg(Evt:%d)", meta.msg_type);
704 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
705 if (ret) {
706 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
707 "ipa_send_msg(Evt:%d)-fail=%d",
708 meta.msg_type, ret);
709 qdf_mem_free(ipa_msg);
710 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800711 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800712}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800713
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800714/**
715 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
716 * @hdd_ipa: HDD IPA local context
717 *
718 * Register IPA UC ready callback function to IPA kernel driver
719 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
720 * open WDI pipe after WLAN driver loading finished
721 *
722 * Return: 0 Success
723 * -EPERM Registration fail
724 */
725static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
726{
727 struct ipa_wdi_uc_ready_params uc_ready_param;
728 int ret = 0;
729
730 hdd_ipa->uc_loaded = false;
731 uc_ready_param.priv = (void *)hdd_ipa;
732 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
733 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
734 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
735 "UC Ready CB register fail");
736 return -EPERM;
737 }
738 if (true == uc_ready_param.is_uC_ready) {
739 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "UC Ready");
740 hdd_ipa->uc_loaded = true;
741 } else {
742 ret = hdd_ipa_uc_send_wdi_control_msg(false);
743 }
744
745 return ret;
746}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800747#else
748static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
749 enum ipa_client_type client)
750{
751 /* Do nothing */
752}
753
754static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
755{
756 hdd_ipa->uc_loaded = true;
757 return 0;
758}
759
760static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
761{
762 return 0;
763}
764#endif
765
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800766/**
767 * hdd_ipa_is_enabled() - Is IPA enabled?
768 * @hdd_ctx: Global HDD context
769 *
770 * Return: true if IPA is enabled, false otherwise
771 */
772bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
773{
774 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
775}
776
777/**
778 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
779 * @hdd_ctx: Global HDD context
780 *
781 * Return: true if IPA uC offload is enabled, false otherwise
782 */
783bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
784{
785 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
786}
787
788/**
789 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
790 * @hdd_ctx: Global HDD context
791 *
792 * Return: true if STA mode IPA uC offload is enabled, false otherwise
793 */
794static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
795{
796 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
797}
798
799/**
Guolei Bianca144d82016-11-10 11:07:42 +0800800 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
801 * @hdd_ipa: Global HDD IPA context
802 *
803 * Return: None
804 */
805#ifdef IPA_UC_STA_OFFLOAD
806static inline void hdd_ipa_uc_sta_reset_sta_connected(
807 struct hdd_ipa_priv *hdd_ipa)
808{
809 vos_lock_acquire(&hdd_ipa->event_lock);
810 hdd_ipa->sta_connected = 0;
811 vos_lock_release(&hdd_ipa->event_lock);
812}
813#else
814static inline void hdd_ipa_uc_sta_reset_sta_connected(
815 struct hdd_ipa_priv *hdd_ipa)
816{
817}
818#endif
819
820/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800821 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
822 * @hdd_ipa: Global HDD IPA context
823 *
824 * Return: true if pre-filter is enabled, otherwise false
825 */
826static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
827{
828 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
829 HDD_IPA_PRE_FILTER_ENABLE_MASK);
830}
831
832/**
833 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
834 * @hdd_ipa: Global HDD IPA context
835 *
836 * Return: true if IPv6 is enabled, otherwise false
837 */
838static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
839{
840 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
841}
842
843/**
844 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
845 * @hdd_ipa: Global HDD IPA context
846 *
847 * Return: true if resource manager is enabled, otherwise false
848 */
849static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
850{
851 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
852}
853
854/**
855 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
856 * @hdd_ipa: Global HDD IPA context
857 *
858 * Return: true if resource manager is enabled, otherwise false
859 */
860static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
861{
862 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
863}
864
865/**
866 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
867 * @hdd_ipa: Global HDD IPA context
868 *
869 * Return: true if clock scaling is enabled, otherwise false
870 */
871static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
872{
873 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
874 HDD_IPA_CLK_SCALING_ENABLE_MASK |
875 HDD_IPA_RM_ENABLE_MASK);
876}
877
878/**
879 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
880 * @ctext: pointer to hdd context.
881 *
882 * If rt debug enabled, periodically called, and fill debug buffer
883 *
884 * Return: none
885 */
886static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
887{
888 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
889 struct hdd_ipa_priv *hdd_ipa;
890 struct uc_rt_debug_info *dump_info = NULL;
891
892 if (wlan_hdd_validate_context(hdd_ctx))
893 return;
894
895 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800896 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800897 "%s: IPA UC is not enabled", __func__);
898 return;
899 }
900
901 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
902
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530903 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800904 dump_info = &hdd_ipa->rt_bug_buffer[
905 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
906
Deepthi Gowri6acee342016-10-28 15:00:38 +0530907 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800908 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
909 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
910 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800911 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800912 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
913 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800914 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
915 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530916 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917
Anurag Chouhan210db072016-02-22 18:42:15 +0530918 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800919 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
920}
921
922/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700923 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924 * @hdd_ctx: pointer to hdd context.
925 *
926 * If rt debug enabled, dump debug buffer contents based on requirement
927 *
928 * Return: none
929 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700930static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931{
932 struct hdd_ipa_priv *hdd_ipa;
933 unsigned int dump_count;
934 unsigned int dump_index;
935 struct uc_rt_debug_info *dump_info = NULL;
936
937 if (wlan_hdd_validate_context(hdd_ctx))
938 return;
939
940 hdd_ipa = hdd_ctx->hdd_ipa;
941 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800942 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800943 "%s: IPA UC is not enabled", __func__);
944 return;
945 }
946
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530947 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800948 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530949 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800950 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530952 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800953 for (dump_count = 0;
954 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
955 dump_count++) {
956 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
957 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
958 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530959 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530960 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800961 dump_info->time, dump_info->ipa_excep_count,
962 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800963 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964 dump_info->rx_destructor_call,
965 dump_info->rx_discard_count);
966 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530967 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530968 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800969 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
970}
971
972/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700973 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
974 * __hdd_ipa_uc_rt_debug_host_dump
975 * @hdd_ctx: pointer to hdd context.
976 *
977 * If rt debug enabled, dump debug buffer contents based on requirement
978 *
979 * Return: none
980 */
981void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
982{
983 cds_ssr_protect(__func__);
984 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
985 cds_ssr_unprotect(__func__);
986}
987
988/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
990 * @ctext: pointer to hdd context.
991 *
992 * periodically called by timer expire
993 * will try to alloc dummy memory and detect out of memory condition
994 * if out of memory detected, dump wlan-ipa stats
995 *
996 * Return: none
997 */
998static void hdd_ipa_uc_rt_debug_handler(void *ctext)
999{
1000 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001001 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001002 void *dummy_ptr = NULL;
1003
1004 if (wlan_hdd_validate_context(hdd_ctx))
1005 return;
1006
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001007 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1008
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001009 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001010 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011 return;
1012 }
1013
1014 /* Allocate dummy buffer periodically and free immediately. this will
1015 * proactively detect OOM and if allocation fails dump ipa stats
1016 */
1017 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
1018 GFP_KERNEL | GFP_ATOMIC);
1019 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001020 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1021 hdd_ipa_uc_stat_request(
Krunal Sonibe766b02016-03-10 13:00:44 -08001022 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001023 } else {
1024 kfree(dummy_ptr);
1025 }
1026
Anurag Chouhan210db072016-02-22 18:42:15 +05301027 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 HDD_IPA_UC_RT_DEBUG_PERIOD);
1029}
1030
1031/**
Yun Parkb187d542016-11-14 18:10:04 -08001032 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001033 * @skb: packet pinter
1034 *
1035 * when free data packet, will be invoked by wlan client and will increase
1036 * free counter
1037 *
1038 * Return: none
1039 */
Jeff Johnsond7720632016-10-05 16:04:32 -07001040static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001041{
1042 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301043 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044 "%s: invalid hdd context", __func__);
1045 return;
1046 }
1047
1048 ghdd_ipa->ipa_rx_destructor_count++;
1049}
1050
1051/**
Yun Parkb187d542016-11-14 18:10:04 -08001052 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001053 * @hdd_ctx: hdd main context
1054 *
1055 * free all rt debugging resources
1056 *
1057 * Return: none
1058 */
1059static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
1060{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001061 struct hdd_ipa_priv *hdd_ipa;
1062
1063 if (wlan_hdd_validate_context(hdd_ctx))
1064 return;
1065
1066 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001067
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301068 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069
1070 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001071 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001072 return;
1073 }
1074
Anurag Chouhan210db072016-02-22 18:42:15 +05301075 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001076 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1077 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1078 }
1079 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1080
1081 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301082 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1083 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301085 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001086}
1087
1088/**
Yun Parkb187d542016-11-14 18:10:04 -08001089 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001090 * @hdd_ctx: hdd main context
1091 *
1092 * alloc and initialize all rt debugging resources
1093 *
1094 * Return: none
1095 */
1096static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
1097{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001098 struct hdd_ipa_priv *hdd_ipa;
1099
1100 if (wlan_hdd_validate_context(hdd_ctx))
1101 return;
1102
1103 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001104
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301105 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301107 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108 sizeof(struct uc_rt_debug_info) *
1109 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1110 hdd_ipa->ipa_tx_forward = 0;
1111 hdd_ipa->ipa_rx_discard = 0;
1112 hdd_ipa->ipa_rx_net_send_count = 0;
1113 hdd_ipa->ipa_rx_internel_drop_count = 0;
1114 hdd_ipa->ipa_rx_destructor_count = 0;
1115
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001116 /* Reatime debug enable on feature enable */
1117 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001118 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001119 return;
1120 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001121
1122 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1123 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1124 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1125 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1126
Anurag Chouhan210db072016-02-22 18:42:15 +05301127 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301129 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130 HDD_IPA_UC_RT_DEBUG_PERIOD);
1131
1132}
1133
1134/**
Yun Parkb187d542016-11-14 18:10:04 -08001135 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1136 * @hdd_ipa: HDD IPA struct
1137 *
1138 * Dump entries in struct hdd_ipa
1139 *
1140 * Return: none
1141 */
1142static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1143{
1144 int i;
1145
1146 /* HDD IPA */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001147 hdd_info("==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001148 "num_iface: %d\n"
1149 "rm_state: %d\n"
1150 "rm_lock: %p\n"
1151 "uc_rm_work: %p\n"
1152 "uc_op_work: %p\n"
1153 "wake_lock: %p\n"
1154 "wake_lock_work: %p\n"
1155 "wake_lock_released: %d\n"
1156 "prod_client: %d\n"
1157 "tx_ref_cnt: %d\n"
1158 "pm_queue_head----\n"
1159 "\thead: %p\n"
1160 "\ttail: %p\n"
1161 "\tqlen: %d\n"
1162 "pm_work: %p\n"
1163 "pm_lock: %p\n"
1164 "suspended: %d\n",
1165 hdd_ipa->num_iface,
1166 hdd_ipa->rm_state,
1167 &hdd_ipa->rm_lock,
1168 &hdd_ipa->uc_rm_work,
1169 &hdd_ipa->uc_op_work,
1170 &hdd_ipa->wake_lock,
1171 &hdd_ipa->wake_lock_work,
1172 hdd_ipa->wake_lock_released,
1173 hdd_ipa->prod_client,
1174 hdd_ipa->tx_ref_cnt.counter,
1175 hdd_ipa->pm_queue_head.head,
1176 hdd_ipa->pm_queue_head.tail,
1177 hdd_ipa->pm_queue_head.qlen,
1178 &hdd_ipa->pm_work,
1179 &hdd_ipa->pm_lock,
1180 hdd_ipa->suspended);
Srinivas Girigowda97852372017-03-06 16:52:59 -08001181 hdd_info("\npending_hw_desc_cnt: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001182 "hw_desc_cnt: %d\n"
1183 "q_lock: %p\n"
1184 "freeq_cnt: %d\n"
1185 "free_desc_head----\n"
1186 "\tnext: %p\n"
1187 "\tprev: %p\n"
1188 "pend_q_cnt: %d\n"
1189 "pend_desc_head----\n"
1190 "\tnext: %p\n"
1191 "\tprev: %p\n"
1192 "hdd_ctx: %p\n"
1193 "debugfs_dir: %p\n"
1194 "stats: %p\n"
1195 "ipv4_notifier: %p\n"
1196 "curr_prod_bw: %d\n"
1197 "curr_cons_bw: %d\n"
1198 "activated_fw_pipe: %d\n"
1199 "sap_num_connected_sta: %d\n"
1200 "sta_connected: %d\n",
1201 hdd_ipa->pending_hw_desc_cnt,
1202 hdd_ipa->hw_desc_cnt,
1203 &hdd_ipa->q_lock,
1204 hdd_ipa->freeq_cnt,
1205 hdd_ipa->free_desc_head.next,
1206 hdd_ipa->free_desc_head.prev,
1207 hdd_ipa->pend_q_cnt,
1208 hdd_ipa->pend_desc_head.next,
1209 hdd_ipa->pend_desc_head.prev,
1210 hdd_ipa->hdd_ctx,
1211 hdd_ipa->debugfs_dir,
1212 &hdd_ipa->stats,
1213 &hdd_ipa->ipv4_notifier,
1214 hdd_ipa->curr_prod_bw,
1215 hdd_ipa->curr_cons_bw,
1216 hdd_ipa->activated_fw_pipe,
1217 hdd_ipa->sap_num_connected_sta,
1218 (unsigned int)hdd_ipa->sta_connected
1219 );
Srinivas Girigowda97852372017-03-06 16:52:59 -08001220 hdd_info("\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001221 "rx_pipe_handle: 0x%x\n"
1222 "resource_loading: %d\n"
1223 "resource_unloading: %d\n"
1224 "pending_cons_req: %d\n"
1225 "pending_event----\n"
1226 "\tanchor.next: %p\n"
1227 "\tanchor.prev: %p\n"
1228 "\tcount: %d\n"
1229 "\tmax_size: %d\n"
1230 "event_lock: %p\n"
1231 "ipa_tx_packets_diff: %d\n"
1232 "ipa_rx_packets_diff: %d\n"
1233 "ipa_p_tx_packets: %d\n"
1234 "ipa_p_rx_packets: %d\n"
1235 "stat_req_reason: %d\n",
1236 hdd_ipa->tx_pipe_handle,
1237 hdd_ipa->rx_pipe_handle,
1238 hdd_ipa->resource_loading,
1239 hdd_ipa->resource_unloading,
1240 hdd_ipa->pending_cons_req,
1241 hdd_ipa->pending_event.anchor.next,
1242 hdd_ipa->pending_event.anchor.prev,
1243 hdd_ipa->pending_event.count,
1244 hdd_ipa->pending_event.max_size,
1245 &hdd_ipa->event_lock,
1246 hdd_ipa->ipa_tx_packets_diff,
1247 hdd_ipa->ipa_rx_packets_diff,
1248 hdd_ipa->ipa_p_tx_packets,
1249 hdd_ipa->ipa_p_rx_packets,
1250 hdd_ipa->stat_req_reason);
1251
Srinivas Girigowda97852372017-03-06 16:52:59 -08001252 hdd_info("assoc_stas_map([id]is_reserved/sta_id): ");
Yun Parkb187d542016-11-14 18:10:04 -08001253 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001254 hdd_info(" [%d]%d/%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001255 hdd_ipa->assoc_stas_map[i].is_reserved,
1256 hdd_ipa->assoc_stas_map[i].sta_id);
1257 }
1258}
1259
1260/**
1261 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1262 * @hdd_ipa: HDD IPA struct
1263 *
1264 * Dump entire struct hdd_ipa_sys_pipe
1265 *
1266 * Return: none
1267 */
1268static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1269{
1270 int i;
1271
1272 /* IPA SYS Pipes */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001273 hdd_info("==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001274
1275 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1276 struct hdd_ipa_sys_pipe *sys_pipe;
1277 struct ipa_sys_connect_params *ipa_sys_params;
1278
1279 sys_pipe = &hdd_ipa->sys_pipe[i];
1280 ipa_sys_params = &sys_pipe->ipa_sys_params;
1281
Srinivas Girigowda97852372017-03-06 16:52:59 -08001282 hdd_info("sys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001283 "\tconn_hdl: 0x%x\n"
1284 "\tconn_hdl_valid: %d\n"
1285 "\tnat_en: %d\n"
1286 "\thdr_len %d\n"
1287 "\thdr_additional_const_len: %d\n"
1288 "\thdr_ofst_pkt_size_valid: %d\n"
1289 "\thdr_ofst_pkt_size: %d\n"
1290 "\thdr_little_endian: %d\n"
1291 "\tmode: %d\n"
1292 "\tclient: %d\n"
1293 "\tdesc_fifo_sz: %d\n"
1294 "\tpriv: %p\n"
1295 "\tnotify: %p\n"
1296 "\tskip_ep_cfg: %d\n"
1297 "\tkeep_ipa_awake: %d\n",
1298 i,
1299 sys_pipe->conn_hdl,
1300 sys_pipe->conn_hdl_valid,
1301 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1302 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1303 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1304 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1305 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1306 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1307 ipa_sys_params->ipa_ep_cfg.mode.mode,
1308 ipa_sys_params->client,
1309 ipa_sys_params->desc_fifo_sz,
1310 ipa_sys_params->priv,
1311 ipa_sys_params->notify,
1312 ipa_sys_params->skip_ep_cfg,
1313 ipa_sys_params->keep_ipa_awake);
1314 }
1315}
1316
1317/**
1318 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1319 * @hdd_ipa: HDD IPA struct
1320 *
1321 * Dump entire struct hdd_ipa_iface_context
1322 *
1323 * Return: none
1324 */
1325static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1326{
1327 int i;
1328
1329 /* IPA Interface Contexts */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001330 hdd_info("==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001331
1332 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1333 struct hdd_ipa_iface_context *iface_context;
1334
1335 iface_context = &hdd_ipa->iface_context[i];
1336
Srinivas Girigowda97852372017-03-06 16:52:59 -08001337 hdd_info("iface_context[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001338 "\thdd_ipa: %p\n"
1339 "\tadapter: %p\n"
1340 "\ttl_context: %p\n"
1341 "\tcons_client: %d\n"
1342 "\tprod_client: %d\n"
1343 "\tiface_id: %d\n"
1344 "\tsta_id: %d\n"
1345 "\tinterface_lock: %p\n"
1346 "\tifa_address: 0x%x\n",
1347 i,
1348 iface_context->hdd_ipa,
1349 iface_context->adapter,
1350 iface_context->tl_context,
1351 iface_context->cons_client,
1352 iface_context->prod_client,
1353 iface_context->iface_id,
1354 iface_context->sta_id,
1355 &iface_context->interface_lock,
1356 iface_context->ifa_address);
1357 }
1358}
1359
1360/**
1361 * hdd_ipa_dump_info() - dump HDD IPA struct
1362 * @pHddCtx: hdd main context
1363 *
1364 * Dump entire struct hdd_ipa
1365 *
1366 * Return: none
1367 */
1368void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1369{
1370 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1371
1372 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1373 hdd_ipa_dump_sys_pipe(hdd_ipa);
1374 hdd_ipa_dump_iface_context(hdd_ipa);
1375}
1376
1377/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001378 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1379 * enabled
1380 *
1381 * This routine is called to set TX flow info if IPA is enabled
1382 *
1383 * Return: None
1384 */
1385void hdd_ipa_set_tx_flow_info(void)
1386{
1387 hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL;
1388 QDF_STATUS status;
1389 hdd_adapter_t *adapter;
1390 hdd_station_ctx_t *pHddStaCtx;
1391 hdd_ap_ctx_t *hdd_ap_ctx;
1392 hdd_hostapd_state_t *hostapd_state;
1393 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1394 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1395 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1396 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1397 const char *p2pMode = "DEV";
1398 hdd_context_t *hdd_ctx;
1399 cds_context_type *cds_ctx;
1400#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1401 uint8_t targetChannel = 0;
1402 uint8_t preAdapterChannel = 0;
1403 uint8_t channel24;
1404 uint8_t channel5;
1405 hdd_adapter_t *preAdapterContext = NULL;
1406 hdd_adapter_t *adapter2_4 = NULL;
1407 hdd_adapter_t *adapter5 = NULL;
1408 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1409#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1410 struct wlan_objmgr_psoc *psoc;
1411
1412 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1413 if (!hdd_ctx) {
1414 cds_err("HDD context is NULL");
1415 return;
1416 }
1417
1418 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1419 if (!cds_ctx) {
1420 cds_err("Invalid CDS Context");
1421 return;
1422 }
1423
1424 psoc = hdd_ctx->hdd_psoc;
1425 status = hdd_get_front_adapter(hdd_ctx, &adapterNode);
1426 while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) {
1427 adapter = adapterNode->pAdapter;
1428 switch (adapter->device_mode) {
1429 case QDF_STA_MODE:
1430 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1431 if (eConnectionState_Associated ==
1432 pHddStaCtx->conn_info.connState) {
1433 staChannel =
1434 pHddStaCtx->conn_info.operationChannel;
1435 qdf_copy_macaddr(&staBssid,
1436 &pHddStaCtx->conn_info.bssId);
1437#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1438 targetChannel = staChannel;
1439#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1440 }
1441 break;
1442 case QDF_P2P_CLIENT_MODE:
1443 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1444 if (eConnectionState_Associated ==
1445 pHddStaCtx->conn_info.connState) {
1446 p2pChannel =
1447 pHddStaCtx->conn_info.operationChannel;
1448 qdf_copy_macaddr(&p2pBssid,
1449 &pHddStaCtx->conn_info.bssId);
1450 p2pMode = "CLI";
1451#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1452 targetChannel = p2pChannel;
1453#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1454 }
1455 break;
1456 case QDF_P2P_GO_MODE:
1457 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1458 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1459 if (hostapd_state->bssState == BSS_START
1460 && hostapd_state->qdf_status ==
1461 QDF_STATUS_SUCCESS) {
1462 p2pChannel = hdd_ap_ctx->operatingChannel;
1463 qdf_copy_macaddr(&p2pBssid,
1464 &adapter->macAddressCurrent);
1465#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1466 targetChannel = p2pChannel;
1467#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1468 }
1469 p2pMode = "GO";
1470 break;
1471 case QDF_SAP_MODE:
1472 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1473 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1474 if (hostapd_state->bssState == BSS_START
1475 && hostapd_state->qdf_status ==
1476 QDF_STATUS_SUCCESS) {
1477 apChannel = hdd_ap_ctx->operatingChannel;
1478 qdf_copy_macaddr(&apBssid,
1479 &adapter->macAddressCurrent);
1480#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1481 targetChannel = apChannel;
1482#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1483 }
1484 break;
1485 case QDF_IBSS_MODE:
1486 default:
1487 break;
1488 }
1489#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1490 if (targetChannel) {
1491 /*
1492 * This is first adapter detected as active
1493 * set as default for none concurrency case
1494 */
1495 if (!preAdapterChannel) {
1496 /* If IPA UC data path is enabled,
1497 * target should reserve extra tx descriptors
1498 * for IPA data path.
1499 * Then host data path should allow less TX
1500 * packet pumping in case IPA
1501 * data path enabled
1502 */
1503 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1504 (QDF_SAP_MODE == adapter->device_mode)) {
1505 adapter->tx_flow_low_watermark =
1506 hdd_ctx->config->TxFlowLowWaterMark +
1507 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1508 } else {
1509 adapter->tx_flow_low_watermark =
1510 hdd_ctx->config->
1511 TxFlowLowWaterMark;
1512 }
1513 adapter->tx_flow_high_watermark_offset =
1514 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1515 cdp_fc_ll_set_tx_pause_q_depth(soc,
1516 adapter->sessionId,
1517 hdd_ctx->config->TxFlowMaxQueueDepth);
1518 cds_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
1519 adapter->device_mode,
1520 targetChannel,
1521 adapter->tx_flow_low_watermark,
1522 adapter->tx_flow_low_watermark +
1523 adapter->tx_flow_high_watermark_offset,
1524 hdd_ctx->config->TxFlowMaxQueueDepth);
1525 preAdapterChannel = targetChannel;
1526 preAdapterContext = adapter;
1527 } else {
1528 /*
1529 * SCC, disable TX flow control for both
1530 * SCC each adapter cannot reserve dedicated
1531 * channel resource, as a result, if any adapter
1532 * blocked OS Q by flow control,
1533 * blocked adapter will lost chance to recover
1534 */
1535 if (preAdapterChannel == targetChannel) {
1536 /* Current adapter */
1537 adapter->tx_flow_low_watermark = 0;
1538 adapter->
1539 tx_flow_high_watermark_offset = 0;
1540 cdp_fc_ll_set_tx_pause_q_depth(soc,
1541 adapter->sessionId,
1542 hdd_ctx->config->
1543 TxHbwFlowMaxQueueDepth);
1544 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1545 hdd_device_mode_to_string(
1546 adapter->device_mode),
1547 adapter->device_mode,
1548 targetChannel,
1549 adapter->tx_flow_low_watermark,
1550 adapter->tx_flow_low_watermark +
1551 adapter->
1552 tx_flow_high_watermark_offset,
1553 hdd_ctx->config->
1554 TxHbwFlowMaxQueueDepth);
1555
1556 if (!preAdapterContext) {
1557 cds_err("SCC: Previous adapter context NULL");
1558 continue;
1559 }
1560
1561 /* Previous adapter */
1562 preAdapterContext->
1563 tx_flow_low_watermark = 0;
1564 preAdapterContext->
1565 tx_flow_high_watermark_offset = 0;
1566 cdp_fc_ll_set_tx_pause_q_depth(soc,
1567 preAdapterContext->sessionId,
1568 hdd_ctx->config->
1569 TxHbwFlowMaxQueueDepth);
1570 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1571 hdd_device_mode_to_string(
1572 preAdapterContext->device_mode
1573 ),
1574 preAdapterContext->device_mode,
1575 targetChannel,
1576 preAdapterContext->
1577 tx_flow_low_watermark,
1578 preAdapterContext->
1579 tx_flow_low_watermark +
1580 preAdapterContext->
1581 tx_flow_high_watermark_offset,
1582 hdd_ctx->config->
1583 TxHbwFlowMaxQueueDepth);
1584 }
1585 /*
1586 * MCC, each adapter will have dedicated
1587 * resource
1588 */
1589 else {
1590 /* current channel is 2.4 */
1591 if (targetChannel <=
1592 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1593 channel24 = targetChannel;
1594 channel5 = preAdapterChannel;
1595 adapter2_4 = adapter;
1596 adapter5 = preAdapterContext;
1597 } else {
1598 /* Current channel is 5 */
1599 channel24 = preAdapterChannel;
1600 channel5 = targetChannel;
1601 adapter2_4 = preAdapterContext;
1602 adapter5 = adapter;
1603 }
1604
1605 if (!adapter5) {
1606 cds_err("MCC: 5GHz adapter context NULL");
1607 continue;
1608 }
1609 adapter5->tx_flow_low_watermark =
1610 hdd_ctx->config->
1611 TxHbwFlowLowWaterMark;
1612 adapter5->
1613 tx_flow_high_watermark_offset =
1614 hdd_ctx->config->
1615 TxHbwFlowHighWaterMarkOffset;
1616 cdp_fc_ll_set_tx_pause_q_depth(soc,
1617 adapter5->sessionId,
1618 hdd_ctx->config->
1619 TxHbwFlowMaxQueueDepth);
1620 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1621 hdd_device_mode_to_string(
1622 adapter5->device_mode),
1623 adapter5->device_mode,
1624 channel5,
1625 adapter5->tx_flow_low_watermark,
1626 adapter5->
1627 tx_flow_low_watermark +
1628 adapter5->
1629 tx_flow_high_watermark_offset,
1630 hdd_ctx->config->
1631 TxHbwFlowMaxQueueDepth);
1632
1633 if (!adapter2_4) {
1634 cds_err("MCC: 2.4GHz adapter context NULL");
1635 continue;
1636 }
1637 adapter2_4->tx_flow_low_watermark =
1638 hdd_ctx->config->
1639 TxLbwFlowLowWaterMark;
1640 adapter2_4->
1641 tx_flow_high_watermark_offset =
1642 hdd_ctx->config->
1643 TxLbwFlowHighWaterMarkOffset;
1644 cdp_fc_ll_set_tx_pause_q_depth(soc,
1645 adapter2_4->sessionId,
1646 hdd_ctx->config->
1647 TxLbwFlowMaxQueueDepth);
1648 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1649 hdd_device_mode_to_string(
1650 adapter2_4->device_mode),
1651 adapter2_4->device_mode,
1652 channel24,
1653 adapter2_4->
1654 tx_flow_low_watermark,
1655 adapter2_4->
1656 tx_flow_low_watermark +
1657 adapter2_4->
1658 tx_flow_high_watermark_offset,
1659 hdd_ctx->config->
1660 TxLbwFlowMaxQueueDepth);
1661
1662 }
1663 }
1664 }
1665 targetChannel = 0;
1666#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1667 status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext);
1668 adapterNode = pNext;
1669 }
1670 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1671}
1672
1673/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001674 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001675 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001676 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1677 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001678 *
1679 * Return: true if IPA is enabled, false otherwise
1680 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001681static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001682 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1683{
1684 struct hdd_ipa_priv *hdd_ipa;
1685
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686 *ipa_tx_diff = 0;
1687 *ipa_rx_diff = 0;
1688
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001689 if (wlan_hdd_validate_context(hdd_ctx))
1690 return;
1691
1692 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1693
1694 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1695 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001696 return;
1697 }
1698
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301699 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1701 (false == hdd_ipa->resource_loading)) {
1702 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1703 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001704 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001705 *ipa_tx_diff, *ipa_rx_diff);
1706 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301707 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001708}
1709
1710/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001711 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1712 * @hdd_ctx: Global HDD context
1713 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1714 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1715 *
1716 * Return: true if IPA is enabled, false otherwise
1717 */
1718void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1719 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1720{
1721 cds_ssr_protect(__func__);
1722 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1723 cds_ssr_unprotect(__func__);
1724}
1725
1726/**
1727 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001728 * @adapter: network adapter
1729 * @reason: STAT REQ Reason
1730 *
1731 * Return: None
1732 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001733static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001735 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736 struct hdd_ipa_priv *hdd_ipa;
1737
1738 if (!adapter) {
1739 return;
1740 }
1741
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001742 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1743
1744 if (wlan_hdd_validate_context(hdd_ctx))
1745 return;
1746
1747 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1748 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1749 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001750 return;
1751 }
1752
Yun Parkb187d542016-11-14 18:10:04 -08001753 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301754 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001755 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1756 (false == hdd_ipa->resource_loading)) {
1757 hdd_ipa->stat_req_reason = reason;
1758 wma_cli_set_command(
1759 (int)adapter->sessionId,
1760 (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
1761 0, VDEV_CMD);
1762 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301763 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001764}
1765
1766/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001767 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1768 * @adapter: network adapter
1769 * @reason: STAT REQ Reason
1770 *
1771 * Return: None
1772 */
1773void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1774{
1775 cds_ssr_protect(__func__);
1776 __hdd_ipa_uc_stat_request(adapter, reason);
1777 cds_ssr_unprotect(__func__);
1778}
1779
1780/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001781 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1782 * @hdd_ipa: Global HDD IPA context
1783 * @sta_add: Should station be added
1784 * @sta_id: ID of the station being queried
1785 *
1786 * Return: true if the station was found
1787 */
1788static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1789 bool sta_add, uint8_t sta_id)
1790{
1791 bool sta_found = false;
1792 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001793
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1795 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1796 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1797 sta_found = true;
1798 break;
1799 }
1800 }
1801 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301802 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001803 "%s: STA ID %d already exist, cannot add",
1804 __func__, sta_id);
1805 return sta_found;
1806 }
1807 if (sta_add) {
1808 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1809 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1810 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1811 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1812 return sta_found;
1813 }
1814 }
1815 }
1816 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301817 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001818 "%s: STA ID %d does not exist, cannot delete",
1819 __func__, sta_id);
1820 return sta_found;
1821 }
1822 if (!sta_add) {
1823 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1824 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1825 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1826 hdd_ipa->assoc_stas_map[idx].is_reserved =
1827 false;
1828 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1829 return sta_found;
1830 }
1831 }
1832 }
1833 return sta_found;
1834}
1835
1836/**
1837 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1838 * @hdd_ipa: Global HDD IPA context
1839 *
1840 * Return: 0 on success, negative errno if error
1841 */
1842static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1843{
1844 int result;
1845 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001846 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001847
1848 /* ACTIVATE TX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001849 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001850 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1851 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001852 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1853 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301854 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001855 "%s: Enable TX PIPE fail, code %d",
1856 __func__, result);
1857 return result;
1858 }
1859 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1860 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301861 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862 "%s: Resume TX PIPE fail, code %d",
1863 __func__, result);
1864 return result;
1865 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001866 cdp_ipa_set_active(soc,
1867 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1868 true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001869
1870 /* ACTIVATE RX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001871 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001872 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1873 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001874 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1875 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301876 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 "%s: Enable RX PIPE fail, code %d",
1878 __func__, result);
1879 return result;
1880 }
1881 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1882 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301883 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001884 "%s: Resume RX PIPE fail, code %d",
1885 __func__, result);
1886 return result;
1887 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001888 cdp_ipa_set_active(soc,
1889 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1890 true, false);
Leo Change3e49442015-10-26 20:07:13 -07001891 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001892 return 0;
1893}
1894
1895/**
1896 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1897 * @hdd_ipa: Global HDD IPA context
1898 *
1899 * Return: 0 on success, negative errno if error
1900 */
1901static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1902{
1903 int result;
1904
Leo Change3e49442015-10-26 20:07:13 -07001905 hdd_ipa->ipa_pipes_down = true;
1906
Srinivas Girigowda97852372017-03-06 16:52:59 -08001907 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
1909 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301910 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911 "%s: Suspend RX PIPE fail, code %d",
1912 __func__, result);
1913 return result;
1914 }
1915 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1916 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301917 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918 "%s: Disable RX PIPE fail, code %d",
1919 __func__, result);
1920 return result;
1921 }
1922
Srinivas Girigowda97852372017-03-06 16:52:59 -08001923 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001924 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
1925 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301926 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927 "%s: Suspend TX PIPE fail, code %d",
1928 __func__, result);
1929 return result;
1930 }
1931 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1932 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301933 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001934 "%s: Disable TX PIPE fail, code %d",
1935 __func__, result);
1936 return result;
1937 }
1938
1939 return 0;
1940}
1941
1942/**
1943 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1944 * @hdd_ipa: Global HDD IPA context
1945 *
1946 * Return: 0 on success, negative errno if error
1947 */
1948static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1949{
1950 hdd_ipa->activated_fw_pipe = 0;
1951 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001952
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953 /* If RM feature enabled
1954 * Request PROD Resource first
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08001955 * PROD resource may return sync or async manners
1956 */
Yun Park4cab6ee2015-10-27 11:43:40 -07001957 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
1958 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1959 /* RM PROD request sync return
1960 * enable pipe immediately
1961 */
1962 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301963 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001964 "%s: IPA WDI Pipe activation failed",
1965 __func__);
1966 hdd_ipa->resource_loading = false;
1967 return -EBUSY;
1968 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001969 }
1970 } else {
1971 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001972 * Just enabled all the PIPEs
1973 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301975 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001976 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001977 __func__);
1978 hdd_ipa->resource_loading = false;
1979 return -EBUSY;
1980 }
1981 hdd_ipa->resource_loading = false;
1982 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001983
Srinivas Girigowda97852372017-03-06 16:52:59 -08001984 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001985 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986 return 0;
1987}
1988
1989/**
1990 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1991 * @hdd_ipa: Global HDD IPA context
1992 *
1993 * Return: None
1994 */
1995static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1996{
1997 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001998 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999
Yun Park7c4f31b2016-11-30 10:09:21 -08002000 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
2001 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2002 QDF_ASSERT(0);
2003 return;
2004 }
2005
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 hdd_ipa->resource_unloading = true;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002007 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW RX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002008 cdp_ipa_set_active(soc,
2009 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2010 false, false);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002011 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW TX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002012 cdp_ipa_set_active(soc,
2013 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2014 false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015}
2016
2017/**
2018 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2019 * @context: User context registered with TL (the IPA Global context is
2020 * registered
2021 * @rxpkt: Packet containing the notification
2022 * @staid: ID of the station associated with the packet
2023 *
2024 * Return: None
2025 */
2026static void
2027hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
2028{
2029 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302030 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031
2032 /*
2033 * When SSR is going on or driver is unloading, just return.
2034 */
2035 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302036 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038
2039 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2040 return;
2041
Srinivas Girigowda97852372017-03-06 16:52:59 -08002042 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043 __func__, event);
2044
2045 switch (event) {
2046 case IPA_RM_RESOURCE_GRANTED:
2047 /* Differed RM Granted */
2048 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302049 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002050 if ((false == hdd_ipa->resource_unloading) &&
2051 (!hdd_ipa->activated_fw_pipe)) {
2052 hdd_ipa_uc_enable_pipes(hdd_ipa);
2053 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302054 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 break;
2056
2057 case IPA_RM_RESOURCE_RELEASED:
2058 /* Differed RM Released */
2059 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002060 break;
2061
2062 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302063 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002064 "%s, invalid event code %d", __func__, event);
2065 break;
2066 }
2067}
2068
2069/**
2070 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2071 * @hdd_ipa: Global HDD IPA context
2072 * @event: IPA resource manager event to be deferred
2073 *
2074 * This function is called when a resource manager event is received
2075 * from firmware in interrupt context. This function will defer the
2076 * handling to the OL RX thread
2077 *
2078 * Return: None
2079 */
2080static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2081{
2082 enum ipa_rm_event event;
2083 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2084 struct uc_rm_work_struct, work);
2085 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2086 struct hdd_ipa_priv, uc_rm_work);
2087
2088 cds_ssr_protect(__func__);
2089 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002090 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002091 "%s, posted event %d", __func__, event);
2092
2093 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2094 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002095}
2096
2097/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002098 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2099 * @ipa_ctxt: hdd ipa local context
2100 *
2101 * Will handle IPA UC image loaded indication comes from IPA kernel
2102 *
2103 * Return: None
2104 */
2105static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt)
2106{
2107 struct ipa_wdi_out_params pipe_out;
2108
2109 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
2110 if (true == ipa_ctxt->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002111 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002112 __func__);
2113 return;
2114 }
2115
2116 ipa_ctxt->uc_loaded = true;
2117 /* Connect pipe */
2118 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2119 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2120 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
2121 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2122 "%s : TX PIPE Handle %d, DBPA 0x%llx",
2123 __func__, ipa_ctxt->tx_pipe_handle,
2124 (unsigned long long) pipe_out.uc_door_bell_pa);
2125
2126 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2127 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
2128 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2129 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2130 "%s : RX PIPE Handle %d, DBPA 0x%llx",
2131 __func__, ipa_ctxt->rx_pipe_handle,
2132 (unsigned long long) pipe_out.uc_door_bell_pa);
2133
2134 /* If already any STA connected, enable IPA/FW PIPEs */
2135 if (ipa_ctxt->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002136 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002137 "Client already connected, enable IPA/FW PIPEs");
2138 hdd_ipa_uc_handle_first_con(ipa_ctxt);
2139 }
2140}
2141
2142/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002143 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2144 * @op_msg: operation message received from firmware
2145 * @usr_ctxt: user context registered with TL (we register the HDD Global
2146 * context)
2147 *
2148 * Return: None
2149 */
2150static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2151{
2152 struct op_msg_type *msg = op_msg;
2153 struct ipa_uc_fw_stats *uc_fw_stat;
2154 struct IpaHwStatsWDIInfoData_t ipa_stat;
2155 struct hdd_ipa_priv *hdd_ipa;
2156 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302157 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002158
2159 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302160 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161 return;
2162 }
2163
2164 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302165 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 "%s, INVALID OPCODE %d", __func__, msg->op_code);
2167 return;
2168 }
2169
2170 hdd_ctx = (hdd_context_t *) usr_ctxt;
2171
2172 /*
2173 * When SSR is going on or driver is unloading, just return.
2174 */
2175 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302176 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302177 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002178 return;
2179 }
2180
2181 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2182
Govind Singhb6a89772016-08-12 11:23:35 +05302183 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002184 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002185
2186 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2187 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302188 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002189 hdd_ipa->activated_fw_pipe++;
2190 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2191 hdd_ipa->resource_loading = false;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002192 if (hdd_ipa->wdi_enabled == false) {
2193 hdd_ipa->wdi_enabled = true;
2194 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2195 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2196 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002197 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002198 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002199 if (hdd_ipa->pending_cons_req)
2200 ipa_rm_notify_completion(
2201 IPA_RM_RESOURCE_GRANTED,
2202 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002203 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002204 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302205 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002206 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002207 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302208 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002209 hdd_ipa->activated_fw_pipe--;
2210 if (!hdd_ipa->activated_fw_pipe) {
2211 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002212 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2213 ipa_rm_release_resource(
2214 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002215 /*
2216 * Sync return success from IPA
2217 * Enable/resume all the PIPEs
2218 */
Yun Park5b635012015-12-02 15:05:01 -08002219 hdd_ipa->resource_unloading = false;
2220 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2221 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002222 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302223 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002224 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002225 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002226 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002227 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302228 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002229 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002230 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002231 "CE RING SIZE: %d\n"
2232 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002233 (unsigned long long)res->ce_sr_base_paddr,
2234 res->ce_sr_ring_size,
2235 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302236 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002237 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002238 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002239 "COMP RING SIZE: %d\n"
2240 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002241 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002242 (unsigned long long)res->tx_comp_ring_base_paddr,
2243 res->tx_comp_ring_size,
2244 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08002245 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302246 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002247 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002248 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002249 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002250 "IND RING DBELL : 0x%llx\n"
2251 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002252 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08002253 "NUM TX FWD OK : %llu\n"
2254 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08002255 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002256 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08002257 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
2258 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002259 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08002260 hdd_ipa->stats.num_tx_fwd_ok,
2261 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302262 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002263 "==== IPA_UC WLAN_HOST CONTROL ====\n"
2264 "SAP NUM STAs: %d\n"
2265 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08002266 "CONCURRENT MODE: %s\n"
2267 "TX PIPE HDL: 0x%x\n"
2268 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002269 "RSC LOADING : %d\n"
2270 "RSC UNLOADING : %d\n"
2271 "PNDNG CNS RQT : %d",
2272 hdd_ipa->sap_num_connected_sta,
2273 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08002274 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002275 hdd_ipa->tx_pipe_handle,
2276 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08002277 hdd_ipa->resource_loading,
2278 hdd_ipa->resource_unloading,
2279 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002280
2281 /* STATs from FW */
2282 uc_fw_stat = (struct ipa_uc_fw_stats *)
2283 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302284 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002285 "==== IPA_UC WLAN_FW TX ====\n"
2286 "COMP RING BASE: 0x%x\n"
2287 "COMP RING SIZE: %d\n"
2288 "COMP RING DBELL : 0x%x\n"
2289 "COMP RING DBELL IND VAL : %d\n"
2290 "COMP RING DBELL CACHED VAL : %d\n"
2291 "COMP RING DBELL CACHED VAL : %d\n"
2292 "PKTS ENQ : %d\n"
2293 "PKTS COMP : %d\n"
2294 "IS SUSPEND : %d\n"
2295 "RSVD : 0x%x",
2296 uc_fw_stat->tx_comp_ring_base,
2297 uc_fw_stat->tx_comp_ring_size,
2298 uc_fw_stat->tx_comp_ring_dbell_addr,
2299 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2300 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2301 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2302 uc_fw_stat->tx_pkts_enqueued,
2303 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002304 uc_fw_stat->tx_is_suspend,
2305 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302306 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002307 "==== IPA_UC WLAN_FW RX ====\n"
2308 "IND RING BASE: 0x%x\n"
2309 "IND RING SIZE: %d\n"
2310 "IND RING DBELL : 0x%x\n"
2311 "IND RING DBELL IND VAL : %d\n"
2312 "IND RING DBELL CACHED VAL : %d\n"
2313 "RDY IND ADDR : 0x%x\n"
2314 "RDY IND CACHE VAL : %d\n"
2315 "RFIL IND : %d\n"
2316 "NUM PKT INDICAT : %d\n"
2317 "BUF REFIL : %d\n"
2318 "NUM DROP NO SPC : %d\n"
2319 "NUM DROP NO BUF : %d\n"
2320 "IS SUSPND : %d\n"
2321 "RSVD : 0x%x\n",
2322 uc_fw_stat->rx_ind_ring_base,
2323 uc_fw_stat->rx_ind_ring_size,
2324 uc_fw_stat->rx_ind_ring_dbell_addr,
2325 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2326 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2327 uc_fw_stat->rx_ind_ring_rdidx_addr,
2328 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2329 uc_fw_stat->rx_refill_idx,
2330 uc_fw_stat->rx_num_pkts_indicated,
2331 uc_fw_stat->rx_buf_refilled,
2332 uc_fw_stat->rx_num_ind_drop_no_space,
2333 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002334 uc_fw_stat->rx_is_suspend,
2335 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002336 /* STATs from IPA */
2337 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302338 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339 "==== IPA_UC IPA TX ====\n"
2340 "NUM PROCD : %d\n"
2341 "CE DBELL : 0x%x\n"
2342 "NUM DBELL FIRED : %d\n"
2343 "COMP RNG FULL : %d\n"
2344 "COMP RNG EMPT : %d\n"
2345 "COMP RNG USE HGH : %d\n"
2346 "COMP RNG USE LOW : %d\n"
2347 "BAM FIFO FULL : %d\n"
2348 "BAM FIFO EMPT : %d\n"
2349 "BAM FIFO USE HGH : %d\n"
2350 "BAM FIFO USE LOW : %d\n"
2351 "NUM DBELL : %d\n"
2352 "NUM UNEXP DBELL : %d\n"
2353 "NUM BAM INT HDL : 0x%x\n"
2354 "NUM BAM INT NON-RUN : 0x%x\n"
2355 "NUM QMB INT HDL : 0x%x",
2356 ipa_stat.tx_ch_stats.num_pkts_processed,
2357 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2358 ipa_stat.tx_ch_stats.num_db_fired,
2359 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2360 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2361 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2362 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2363 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2364 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2365 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2366 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2367 ipa_stat.tx_ch_stats.num_db,
2368 ipa_stat.tx_ch_stats.num_unexpected_db,
2369 ipa_stat.tx_ch_stats.num_bam_int_handled,
2370 ipa_stat.tx_ch_stats.
2371 num_bam_int_in_non_runnning_state,
2372 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2373
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302374 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002375 "==== IPA_UC IPA RX ====\n"
2376 "MAX OST PKT : %d\n"
2377 "NUM PKT PRCSD : %d\n"
2378 "RNG RP : 0x%x\n"
2379 "COMP RNG FULL : %d\n"
2380 "COMP RNG EMPT : %d\n"
2381 "COMP RNG USE HGH : %d\n"
2382 "COMP RNG USE LOW : %d\n"
2383 "BAM FIFO FULL : %d\n"
2384 "BAM FIFO EMPT : %d\n"
2385 "BAM FIFO USE HGH : %d\n"
2386 "BAM FIFO USE LOW : %d\n"
2387 "NUM DB : %d\n"
2388 "NUM UNEXP DB : %d\n"
2389 "NUM BAM INT HNDL : 0x%x\n",
2390 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2391 ipa_stat.rx_ch_stats.num_pkts_processed,
2392 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2393 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2394 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2395 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2396 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2397 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2398 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2399 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2400 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2401 ipa_stat.rx_ch_stats.num_db,
2402 ipa_stat.rx_ch_stats.num_unexpected_db,
2403 ipa_stat.rx_ch_stats.num_bam_int_handled);
2404 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2405 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2406 /* STATs from FW */
2407 uc_fw_stat = (struct ipa_uc_fw_stats *)
2408 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302409 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002410 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2411 uc_fw_stat->tx_pkts_completed,
2412 hdd_ipa->ipa_p_tx_packets);
2413 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2414 (uc_fw_stat->rx_num_ind_drop_no_space +
2415 uc_fw_stat->rx_num_ind_drop_no_buf +
2416 uc_fw_stat->rx_num_pkts_indicated),
2417 hdd_ipa->ipa_p_rx_packets);
2418
2419 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2420 hdd_ipa->ipa_p_rx_packets =
2421 (uc_fw_stat->rx_num_ind_drop_no_space +
2422 uc_fw_stat->rx_num_ind_drop_no_buf +
2423 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302424 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002425 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2426 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2427 hdd_ipa_uc_loaded_handler(hdd_ipa);
2428 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002429 } else {
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002430 HDD_IPA_LOG(LOGE, "INVALID REASON %d",
2431 hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302433 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002434}
2435
2436
2437/**
2438 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2439 * @adapter: device adapter instance
2440 * @offload_type: MCC or SCC
2441 * @enable: TX offload enable or disable
2442 *
2443 * Return: none
2444 */
2445static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002446 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002447{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002448 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002449 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002450 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002451 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002452
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002453 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002454 return;
2455
Yun Park8292dcb2016-10-07 16:46:06 -07002456 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002457 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002458
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002459 if (!iface_context) {
2460 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2461 "Interface context is NULL");
2462 return;
2463 }
2464
2465 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002466 /* IPA offload status is already set as desired */
2467 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002468 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
2469 "IPA offload status is already set",
2470 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002471 return;
2472 }
2473
Yun Park4540e862016-11-10 16:30:06 -08002474 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2475 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2476 "invalid session id: %d, offload_type=%d, enable=%d",
2477 adapter->sessionId, offload_type, enable);
2478 return;
2479 }
2480
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302481 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002482 sizeof(ipa_offload_enable_disable));
2483 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002484 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002485 ipa_offload_enable_disable.enable = enable;
2486
Srinivas Girigowda97852372017-03-06 16:52:59 -08002487 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park8292dcb2016-10-07 16:46:06 -07002488 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002489 ipa_offload_enable_disable.offload_type,
2490 ipa_offload_enable_disable.vdev_id,
2491 ipa_offload_enable_disable.enable);
2492
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302493 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002494 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2495 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302496 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002497 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2498 __func__,
2499 ipa_offload_enable_disable.offload_type,
2500 ipa_offload_enable_disable.vdev_id,
2501 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002502 } else {
2503 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002504 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002505 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002506 }
2507}
2508
2509/**
2510 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2511 * @work: uC OP work
2512 *
2513 * Return: None
2514 */
2515static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2516{
2517 struct op_msg_type *msg;
2518 struct uc_op_work_struct *uc_op_work = container_of(work,
2519 struct uc_op_work_struct, work);
2520 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2521
2522 cds_ssr_protect(__func__);
2523
2524 msg = uc_op_work->msg;
2525 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002526 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002527 "%s, posted msg %d", __func__, msg->op_code);
2528
2529 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2530
2531 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002532}
2533
2534/**
2535 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2536 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2537 * @op_msg: operation message received from firmware
2538 * @hdd_ctx: Global HDD context
2539 *
2540 * Return: None
2541 */
2542static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2543{
2544 struct hdd_ipa_priv *hdd_ipa;
2545 struct op_msg_type *msg;
2546 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302547 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002548
2549 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302550 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002551 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002552
2553 msg = (struct op_msg_type *)op_msg;
2554 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2555
2556 if (unlikely(!hdd_ipa))
2557 goto end;
2558
2559 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302560 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002561 __func__, msg->op_code);
2562 goto end;
2563 }
2564
2565 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2566 if (uc_op_work->msg)
2567 /* When the same uC OPCODE is already pended, just return */
2568 goto end;
2569
2570 uc_op_work->msg = msg;
2571 schedule_work(&uc_op_work->work);
2572 return;
2573
2574end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302575 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002576}
2577
2578/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002579 * hdd_ipa_init_uc_op_work - init ipa uc op work
2580 * @work: struct work_struct
2581 * @work_handler: work_handler
2582 *
2583 * Return: none
2584 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002585static void hdd_ipa_init_uc_op_work(struct work_struct *work,
2586 work_func_t work_handler)
2587{
2588 INIT_WORK(work, work_handler);
2589}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002590
Rajeev Kumar217f2172016-01-06 18:11:55 -08002591/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002592 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2593 * @hdd_ctx: Global HDD context
2594 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302595 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002596 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002597QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002598{
2599 struct ipa_wdi_in_params pipe_in;
2600 struct ipa_wdi_out_params pipe_out;
2601 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002602 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07002603 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002604 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2605 int ret;
2606 QDF_STATUS stat = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002607
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002608 ENTER();
2609
Yun Parkbaa62862017-01-18 13:43:34 -08002610 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002611 if (!pdev || !soc) {
2612 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkbaa62862017-01-18 13:43:34 -08002613 stat = QDF_STATUS_E_FAILURE;
2614 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002615 }
Yun Parkbaa62862017-01-18 13:43:34 -08002616
2617 cdp_ipa_get_resource(soc, (void *)pdev, &ipa_ctxt->ipa_resource);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002618 if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) ||
2619 (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2620 (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2621 (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2622 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2623 "IPA UC resource alloc fail");
2624 return QDF_STATUS_E_FAILURE;
2625 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002626 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2627 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302628 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2629 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002630
Anurag Chouhanffb21542016-02-17 14:33:03 +05302631 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302632
2633 if (!cds_is_driver_recovering()) {
2634 qdf_mutex_create(&ipa_ctxt->event_lock);
2635 qdf_mutex_create(&ipa_ctxt->ipa_lock);
2636 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637
2638 /* TX PIPE */
2639 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2640 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2641 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2642 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2643 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2644 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2645 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2646 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2647 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2648 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2649 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2650 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2651 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002652 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2653 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002654 pipe_in.sys.keep_ipa_awake = true;
2655 }
2656
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002657 pipe_in.u.dl.comp_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002658 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002659 pipe_in.u.dl.comp_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002660 ipa_ctxt->ipa_resource.tx_comp_ring_size *
2661 sizeof(qdf_dma_addr_t);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002662 pipe_in.u.dl.ce_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002663 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002664 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
2665 pipe_in.u.dl.ce_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002666 ipa_ctxt->ipa_resource.ce_sr_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002667 pipe_in.u.dl.num_tx_buffers =
Yun Parkbaa62862017-01-18 13:43:34 -08002668 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002669
Yun Parkbaa62862017-01-18 13:43:34 -08002670 qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in,
2671 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002672 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08002673 IPA_CLIENT_WLAN1_CONS);
2674
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002675 if (true == ipa_ctxt->uc_loaded) {
2676 /* Connect WDI IPA PIPE */
Yun Parkbaa62862017-01-18 13:43:34 -08002677 ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2678 if (ret) {
2679 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2680 "ipa_connect_wdi_pipe falied for Tx: ret=%d",
2681 ret);
2682 stat = QDF_STATUS_E_FAILURE;
2683 goto fail_return;
2684 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002685 /* Micro Controller Doorbell register */
Srinivas Girigowda97852372017-03-06 16:52:59 -08002686 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08002687 "CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
2688 (unsigned int)pipe_out.uc_door_bell_pa,
2689 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002690
2691 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Yun Parkbaa62862017-01-18 13:43:34 -08002692
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002693 /* WLAN TX PIPE Handle */
2694 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002695 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08002696 "TX : 0x%x, %d, 0x%x, 0x%x, %d, %d, 0x%x",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002697 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
2698 pipe_in.u.dl.comp_ring_size,
2699 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
2700 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
2701 pipe_in.u.dl.ce_ring_size,
2702 pipe_in.u.dl.num_tx_buffers,
2703 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
2704 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002705
2706 /* RX PIPE */
2707 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2708 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
2709 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
2710 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
2711 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2712 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
2713 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
2714 sizeof(struct sps_iovec);
2715 pipe_in.sys.notify = hdd_ipa_w2i_cb;
2716 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302717 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkbaa62862017-01-18 13:43:34 -08002718 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002719 pipe_in.sys.keep_ipa_awake = true;
2720 }
2721
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002722 pipe_in.u.ul.rdy_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002723 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002724 pipe_in.u.ul.rdy_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002725 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002726 pipe_in.u.ul.rdy_ring_rp_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002727 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002728 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Yun Parkbaa62862017-01-18 13:43:34 -08002729
2730 qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in,
2731 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002732 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08002733 IPA_CLIENT_WLAN1_PROD);
2734
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002735 if (true == ipa_ctxt->uc_loaded) {
Yun Parkbaa62862017-01-18 13:43:34 -08002736 ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2737 if (ret) {
2738 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2739 "ipa_connect_wdi_pipe falied for Rx: ret=%d",
2740 ret);
2741 stat = QDF_STATUS_E_FAILURE;
2742 goto fail_return;
2743
2744 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002745 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2746 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002747 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08002748 "PROD DB pipe out 0x%x TX PIPE Handle 0x%x",
2749 (unsigned int)pipe_out.uc_door_bell_pa,
2750 ipa_ctxt->tx_pipe_handle);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002751 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002752 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
2753 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
2754 pipe_in.u.ul.rdy_ring_size,
2755 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
2756 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
2757 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002758
Yun Parkbaa62862017-01-18 13:43:34 -08002759 cdp_ipa_set_doorbell_paddr(soc, (void *)pdev,
2760 ipa_ctxt->tx_comp_doorbell_paddr,
2761 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002762
Yun Parkbaa62862017-01-18 13:43:34 -08002763 cdp_ipa_register_op_cb(soc, (void *)pdev,
2764 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
2765
2766 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2767 "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x",
2768 pdev->ipa_uc_op_cb,
2769 (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr,
2770 (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002771
2772 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08002773 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Yun Parkbaa62862017-01-18 13:43:34 -08002774 hdd_ipa_uc_fw_op_event_handler);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002775 ipa_ctxt->uc_op_work[i].msg = NULL;
2776 }
2777
Yun Parkbaa62862017-01-18 13:43:34 -08002778fail_return:
2779 EXIT();
2780 return stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002781}
2782
Leo Change3e49442015-10-26 20:07:13 -07002783/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002784 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002785 * @hdd_ctx: hdd main context
2786 *
2787 * Force shutdown IPA pipe
2788 * Independent of FW pipe status, IPA pipe shutdonw progress
2789 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2790 * independent from FW pipe status
2791 *
2792 * Return: NONE
2793 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002794static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002795{
2796 struct hdd_ipa_priv *hdd_ipa;
2797
2798 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2799 return;
2800
2801 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2802 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302803 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07002804 "IPA pipes are not down yet, force shutdown");
2805 hdd_ipa_uc_disable_pipes(hdd_ipa);
2806 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002807 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Leo Change3e49442015-10-26 20:07:13 -07002808 "IPA pipes are down, do nothing");
2809 }
Leo Change3e49442015-10-26 20:07:13 -07002810}
2811
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002812/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002813 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2814 * __hdd_ipa_uc_force_pipe_shutdown
2815 * @hdd_ctx: hdd main context
2816 *
2817 * Force shutdown IPA pipe
2818 * Independent of FW pipe status, IPA pipe shutdonw progress
2819 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2820 * independent from FW pipe status
2821 *
2822 * Return: NONE
2823 */
2824void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2825{
2826 cds_ssr_protect(__func__);
2827 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2828 cds_ssr_unprotect(__func__);
2829}
2830
2831/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302832 * hdd_ipa_msg_free_fn() - Free an IPA message
2833 * @buff: pointer to the IPA message
2834 * @len: length of the IPA message
2835 * @type: type of IPA message
2836 *
2837 * Return: None
2838 */
2839static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2840{
Srinivas Girigowda97852372017-03-06 16:52:59 -08002841 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05302842 ghdd_ipa->stats.num_free_msg++;
2843 qdf_mem_free(buff);
2844}
2845
Govind Singh9c58eba2016-09-02 16:23:06 +05302846/**
jge62037862016-12-09 10:44:33 +08002847 * hdd_ipa_uc_send_evt() - send event to ipa
2848 * @hdd_ctx: pointer to hdd context
2849 * @type: event type
2850 * @mac_addr: pointer to mac address
2851 *
2852 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05302853 *
2854 * Return: 0 - Success
2855 */
jge62037862016-12-09 10:44:33 +08002856static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
2857 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05302858{
jge62037862016-12-09 10:44:33 +08002859 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05302860 struct ipa_msg_meta meta;
2861 struct ipa_wlan_msg *msg;
2862 int ret = 0;
jge62037862016-12-09 10:44:33 +08002863
2864 meta.msg_len = sizeof(struct ipa_wlan_msg);
2865 msg = qdf_mem_malloc(meta.msg_len);
2866 if (msg == NULL) {
2867 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2868 "msg allocation failed");
2869 return -ENOMEM;
2870 }
2871
2872 meta.msg_type = type;
2873 strlcpy(msg->name, adapter->dev->name,
2874 IPA_RESOURCE_NAME_MAX);
2875 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002876 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
jge62037862016-12-09 10:44:33 +08002877 msg->name, meta.msg_type);
2878 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2879 if (ret) {
2880 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2881 "%s: Evt: %d fail:%d",
2882 msg->name, meta.msg_type, ret);
2883 qdf_mem_free(msg);
2884 return ret;
2885 }
2886
2887 hdd_ipa->stats.num_send_msg++;
2888
2889 return ret;
2890}
2891
2892/**
2893 * hdd_ipa_uc_disconnect_client() - send client disconnect event
2894 * @hdd_ctx: pointer to hdd adapter
2895 *
2896 * Send disconnect client event to IPA driver during SSR
2897 *
2898 * Return: 0 - Success
2899 */
2900static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
2901{
2902 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2903 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05302904 int i;
2905
2906 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2907 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2908 continue;
2909 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08002910 (!adapter->aStaInfo[i].isDeauthInProgress) &&
2911 hdd_ipa->sap_num_connected_sta) {
2912 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
2913 adapter->aStaInfo[i].macAddrSTA.bytes);
2914 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05302915 }
2916 }
2917
2918 return ret;
2919}
2920
2921/**
jge62037862016-12-09 10:44:33 +08002922 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
2923 * @hdd_ctx: pointer to hdd adapter
2924 *
2925 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05302926 *
2927 * Return: 0 - Success
2928 */
jge62037862016-12-09 10:44:33 +08002929
2930static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
2931{
2932 int ret = 0;
2933
2934 if (adapter->ipa_context)
2935 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
2936 adapter->dev->dev_addr);
2937
2938 return ret;
2939}
2940
jge62037862016-12-09 10:44:33 +08002941/**
2942 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
2943 * @hdd_ctx: pointer to hdd adapter
2944 *
2945 * Send disconnect sta event to IPA driver during SSR
2946 *
2947 * Return: 0 - Success
2948 */
2949static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2950{
2951 hdd_station_ctx_t *pHddStaCtx;
2952 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2953 int ret = 0;
2954
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002955 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08002956 hdd_ipa->sta_connected) {
2957 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2958 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002959 pHddStaCtx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08002960 }
2961
2962 return ret;
2963}
jge62037862016-12-09 10:44:33 +08002964
2965/**
2966 * hdd_ipa_uc_disconnect() - send disconnect ipa event
2967 * @hdd_ctx: pointer to hdd context
2968 *
2969 * Send disconnect event to IPA driver during SSR
2970 *
2971 * Return: 0 - Success
2972 */
2973static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05302974{
2975 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2976 QDF_STATUS status;
2977 hdd_adapter_t *adapter;
2978 int ret = 0;
2979
Govind Singh9c58eba2016-09-02 16:23:06 +05302980 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2981 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2982 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08002983 if (adapter->device_mode == QDF_SAP_MODE) {
2984 hdd_ipa_uc_disconnect_client(adapter);
2985 hdd_ipa_uc_disconnect_ap(adapter);
2986 } else if (adapter->device_mode == QDF_STA_MODE) {
2987 hdd_ipa_uc_disconnect_sta(adapter);
2988 }
2989
Govind Singh9c58eba2016-09-02 16:23:06 +05302990 status = hdd_get_next_adapter(
2991 hdd_ctx, adapter_node, &next);
2992 adapter_node = next;
2993 }
2994
2995 return ret;
2996}
2997
2998/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002999 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003000 *
3001 * Deinit basic IPA UC host side to be in sync reloaded FW during
3002 * SSR
3003 *
3004 * Return: 0 - Success
3005 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003006static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003007{
3008 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3009 int idx;
3010 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303011 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003012
Arun Khandavallicc544b32017-01-30 19:52:16 +05303013 if (!hdd_ipa)
3014 return 0;
3015
3016 hdd_ctx = hdd_ipa->hdd_ctx;
3017 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 return 0;
3019
jge62037862016-12-09 10:44:33 +08003020 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303021 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003022
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003023 /* Clean up HDD IPA interfaces */
3024 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3025 (idx < HDD_IPA_MAX_IFACE); idx++) {
3026 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003027 if (iface_context->adapter && iface_context->adapter->magic ==
3028 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003029 hdd_ipa_cleanup_iface(iface_context);
3030 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003031 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003032 /* After SSR, wlan driver reloads FW again. But we need to protect
3033 * IPA submodule during SSR transient state. So deinit basic IPA
3034 * UC host side to be in sync with reloaded FW during SSR
3035 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08003036 if (!hdd_ipa->ipa_pipes_down)
3037 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003038
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303039 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003040 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3041 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3042 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3043 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303044 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003045
Srinivas Girigowda97852372017-03-06 16:52:59 -08003046 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Arun Khandavallicc544b32017-01-30 19:52:16 +05303047 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
3048 __func__, hdd_ipa->tx_pipe_handle);
3049 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
3050
Srinivas Girigowda97852372017-03-06 16:52:59 -08003051 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Arun Khandavallicc544b32017-01-30 19:52:16 +05303052 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
3053 __func__, hdd_ipa->rx_pipe_handle);
3054 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
3055
Guolei Bianca144d82016-11-10 11:07:42 +08003056 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3057 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3058
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003059 /* Full IPA driver cleanup not required since wlan driver is now
3060 * unloaded and reloaded after SSR.
3061 */
3062 return 0;
3063}
3064
3065/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003066 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3067 *
3068 * Deinit basic IPA UC host side to be in sync reloaded FW during
3069 * SSR
3070 *
3071 * Return: 0 - Success
3072 */
3073int hdd_ipa_uc_ssr_deinit(void)
3074{
3075 int ret;
3076
3077 cds_ssr_protect(__func__);
3078 ret = __hdd_ipa_uc_ssr_deinit();
3079 cds_ssr_unprotect(__func__);
3080
3081 return ret;
3082}
3083
3084/**
3085 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003086 *
3087 * Init basic IPA UC host side to be in sync with reloaded FW after
3088 * SSR to resume IPA UC operations
3089 *
3090 * Return: 0 - Success
3091 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303092static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003093{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003094
Arun Khandavallicc544b32017-01-30 19:52:16 +05303095 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3096 int i;
3097 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303098
3099 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3100 return 0;
3101
Arun Khandavallicc544b32017-01-30 19:52:16 +05303102 /* Create the interface context */
3103 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3104 iface_context = &hdd_ipa->iface_context[i];
3105 iface_context->hdd_ipa = hdd_ipa;
3106 iface_context->cons_client =
3107 hdd_ipa_adapter_2_client[i].cons_client;
3108 iface_context->prod_client =
3109 hdd_ipa_adapter_2_client[i].prod_client;
3110 iface_context->iface_id = i;
3111 iface_context->adapter = NULL;
3112 }
3113 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3114 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3115 hdd_ipa->vdev_offload_enabled[i] = false;
3116 }
3117
3118 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3119 hdd_ipa->resource_loading = false;
3120 hdd_ipa->resource_unloading = false;
3121 hdd_ipa->sta_connected = 0;
3122 hdd_ipa->ipa_pipes_down = true;
3123 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303124 }
3125
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003126 return 0;
3127}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003128
3129/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003130 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3131 *
3132 * Init basic IPA UC host side to be in sync with reloaded FW after
3133 * SSR to resume IPA UC operations
3134 *
3135 * Return: 0 - Success
3136 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303137int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003138{
3139 int ret;
3140
3141 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303142 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003143 cds_ssr_unprotect(__func__);
3144
3145 return ret;
3146}
3147
3148/**
3149 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08003150 * @hdd_ctx: Global HDD context
3151 * @skb: skb sent to IPA
3152 * @session_id: send packet instance session id
3153 *
3154 * Send TX packet which generated by system to IPA.
3155 * This routine only will be used for function verification
3156 *
3157 * Return: NULL packet sent to IPA properly
3158 * NULL invalid packet drop
3159 * skb packet not sent to IPA. legacy data path should handle
3160 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003161static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08003162 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07003163{
Leo Chang3bc8fed2015-11-13 10:59:47 -08003164 struct ipa_header *ipa_header;
3165 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003166 struct hdd_ipa_priv *hdd_ipa;
3167
3168 if (wlan_hdd_validate_context(hdd_ctx))
3169 return skb;
3170
3171 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003172
3173 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3174 return skb;
3175
Leo Chang07b28f62016-05-11 12:29:22 -07003176 if (!hdd_ipa)
3177 return skb;
3178
3179 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
3180 return skb;
3181
Leo Changcc923e22016-06-16 15:29:03 -07003182 if (skb_headroom(skb) <
3183 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07003184 return skb;
3185
Leo Chang3bc8fed2015-11-13 10:59:47 -08003186 ipa_header = (struct ipa_header *) skb_push(skb,
3187 sizeof(struct ipa_header));
3188 if (!ipa_header) {
3189 /* No headroom, legacy */
3190 return skb;
3191 }
3192 memset(ipa_header, 0, sizeof(*ipa_header));
3193 ipa_header->vdev_id = 0;
3194
3195 frag_header = (struct frag_header *) skb_push(skb,
3196 sizeof(struct frag_header));
3197 if (!frag_header) {
3198 /* No headroom, drop */
3199 kfree_skb(skb);
3200 return NULL;
3201 }
3202 memset(frag_header, 0, sizeof(*frag_header));
3203 frag_header->length = skb->len - sizeof(struct frag_header)
3204 - sizeof(struct ipa_header);
3205
3206 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
3207 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07003208}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003209
3210/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003211 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
3212 * @hdd_ctx: Global HDD context
3213 * @skb: skb sent to IPA
3214 * @session_id: send packet instance session id
3215 *
3216 * Send TX packet which generated by system to IPA.
3217 * This routine only will be used for function verification
3218 *
3219 * Return: NULL packet sent to IPA properly
3220 * NULL invalid packet drop
3221 * skb packet not sent to IPA. legacy data path should handle
3222 */
3223struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
3224 struct sk_buff *skb, uint8_t session_id)
3225{
3226 struct sk_buff *ret;
3227
3228 cds_ssr_protect(__func__);
3229 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
3230 cds_ssr_unprotect(__func__);
3231
3232 return ret;
3233}
3234
3235/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003236 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3237 * @work: scheduled work
3238 *
3239 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3240 * not want to immediately release the wake lock since the system
3241 * would then potentially try to suspend when there is a healthy data
3242 * rate. Deferred work is scheduled and this function handles the
3243 * work. When this function is called, if the IPA resource is still
3244 * released then we release the wake lock.
3245 *
3246 * Return: None
3247 */
3248static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3249{
3250 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3251 struct hdd_ipa_priv,
3252 wake_lock_work);
3253
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303254 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003255
3256 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3257 goto end;
3258
3259 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303260 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003261 WIFI_POWER_EVENT_WAKELOCK_IPA);
3262
3263end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303264 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003265}
3266
3267/**
3268 * hdd_ipa_rm_request() - Request resource from IPA
3269 * @hdd_ipa: Global HDD IPA context
3270 *
3271 * Return: 0 on success, negative errno on error
3272 */
3273static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3274{
3275 int ret = 0;
3276
3277 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3278 return 0;
3279
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303280 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003281
3282 switch (hdd_ipa->rm_state) {
3283 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303284 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003285 return 0;
3286 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303287 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003288 return -EINPROGRESS;
3289 case HDD_IPA_RM_RELEASED:
3290 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3291 break;
3292 }
3293
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303294 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003295
3296 ret = ipa_rm_inactivity_timer_request_resource(
3297 IPA_RM_RESOURCE_WLAN_PROD);
3298
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303299 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003300 if (ret == 0) {
3301 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3302 hdd_ipa->stats.num_rm_grant_imm++;
3303 }
3304
3305 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3306 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303307 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003308 WIFI_POWER_EVENT_WAKELOCK_IPA);
3309 hdd_ipa->wake_lock_released = false;
3310 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303311 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003312
3313 return ret;
3314}
3315
3316/**
3317 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3318 * @hdd_ipa: Global HDD IPA context
3319 *
3320 * Return: 0 if resources released, negative errno otherwise
3321 */
3322static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3323{
3324 int ret = 0;
3325
3326 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3327 return 0;
3328
3329 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3330 return -EAGAIN;
3331
3332 spin_lock_bh(&hdd_ipa->q_lock);
3333 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
3334 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
3335 spin_unlock_bh(&hdd_ipa->q_lock);
3336 return -EAGAIN;
3337 }
3338 spin_unlock_bh(&hdd_ipa->q_lock);
3339
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303340 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003341
Nirav Shahcbc6d722016-03-01 16:24:53 +05303342 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303343 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003344 return -EAGAIN;
3345 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303346 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003347
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303348 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003349 switch (hdd_ipa->rm_state) {
3350 case HDD_IPA_RM_GRANTED:
3351 break;
3352 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303353 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003354 return -EINPROGRESS;
3355 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303356 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003357 return 0;
3358 }
3359
3360 /* IPA driver returns immediately so set the state here to avoid any
3361 * race condition.
3362 */
3363 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3364 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303365 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003366
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003367 ret = ipa_rm_inactivity_timer_release_resource(
3368 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003369
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303370 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003371 if (unlikely(ret != 0)) {
3372 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3373 WARN_ON(1);
3374 }
3375
3376 /*
3377 * If wake_lock is released immediately, kernel would try to suspend
3378 * immediately as well, Just avoid ping-pong between suspend-resume
3379 * while there is healthy amount of data transfer going on by
3380 * releasing the wake_lock after some delay.
3381 */
3382 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3383 msecs_to_jiffies
3384 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3385
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303386 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003387
3388 return ret;
3389}
3390
3391/**
3392 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3393 * @user_data: user data registered with IPA
3394 * @event: the IPA resource manager event that occurred
3395 * @data: the data associated with the event
3396 *
3397 * Return: None
3398 */
3399static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3400 unsigned long data)
3401{
3402 struct hdd_ipa_priv *hdd_ipa = user_data;
3403
3404 if (unlikely(!hdd_ipa))
3405 return;
3406
3407 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3408 return;
3409
Srinivas Girigowda97852372017-03-06 16:52:59 -08003410 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003411
3412 switch (event) {
3413 case IPA_RM_RESOURCE_GRANTED:
3414 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3415 /* RM Notification comes with ISR context
3416 * it should be serialized into work queue to avoid
3417 * ISR sleep problem
3418 */
3419 hdd_ipa->uc_rm_work.event = event;
3420 schedule_work(&hdd_ipa->uc_rm_work.work);
3421 break;
3422 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303423 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003424 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303425 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003426 hdd_ipa->stats.num_rm_grant++;
3427 break;
3428
3429 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003430 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003431 hdd_ipa->resource_unloading = false;
3432 break;
3433
3434 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303435 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003436 break;
3437 }
3438}
3439
3440/**
3441 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3442 *
3443 * Callback function registered with IPA that is called when IPA wants
3444 * to release the WLAN consumer resource
3445 *
3446 * Return: 0 if the request is granted, negative errno otherwise
3447 */
3448static int hdd_ipa_rm_cons_release(void)
3449{
3450 return 0;
3451}
3452
3453/**
3454 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3455 *
3456 * Callback function registered with IPA that is called when IPA wants
3457 * to access the WLAN consumer resource
3458 *
3459 * Return: 0 if the request is granted, negative errno otherwise
3460 */
3461static int hdd_ipa_rm_cons_request(void)
3462{
Yun Park4d8b60a2015-10-22 13:59:32 -07003463 int ret = 0;
3464
3465 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303466 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003467 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003468 __func__);
3469 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003470 ret = -EINPROGRESS;
3471 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303472 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003473 "%s: IPA resource unloading in progress",
3474 __func__);
3475 ghdd_ipa->pending_cons_req = true;
3476 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003477 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003478
3479 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003480}
3481
3482/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003483 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003484 * @hdd_ctx: Global HDD context
3485 * @tx_packets: Number of packets transmitted in the last sample period
3486 * @rx_packets: Number of packets received in the last sample period
3487 *
3488 * Return: 0 on success, negative errno on error
3489 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003490static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003491 uint64_t rx_packets)
3492{
3493 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003494 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003495 struct ipa_rm_perf_profile profile;
3496 int ret;
3497
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003498 if (wlan_hdd_validate_context(hdd_ctx))
3499 return 0;
3500
3501 hdd_ipa = hdd_ctx->hdd_ipa;
3502
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003503 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3504 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3505 return 0;
3506
3507 memset(&profile, 0, sizeof(profile));
3508
3509 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3510 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3511 else if (tx_packets >
3512 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3513 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3514 else
3515 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3516
3517 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3518 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3519 else if (rx_packets >
3520 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3521 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3522 else
3523 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3524
Yun Parkec845302016-12-15 09:22:57 -08003525 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003526 "CONS perf curr: %d, next: %d",
3527 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003528 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003529 "PROD perf curr: %d, next: %d",
3530 hdd_ipa->curr_prod_bw, next_prod_bw);
3531
3532 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003533 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003534 hdd_ipa->curr_cons_bw, next_cons_bw);
3535 profile.max_supported_bandwidth_mbps = next_cons_bw;
3536 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3537 &profile);
3538 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003539 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003540
3541 return ret;
3542 }
3543 hdd_ipa->curr_cons_bw = next_cons_bw;
3544 hdd_ipa->stats.num_cons_perf_req++;
3545 }
3546
3547 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003548 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003549 hdd_ipa->curr_prod_bw, next_prod_bw);
3550 profile.max_supported_bandwidth_mbps = next_prod_bw;
3551 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3552 &profile);
3553 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003554 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003555 return ret;
3556 }
3557 hdd_ipa->curr_prod_bw = next_prod_bw;
3558 hdd_ipa->stats.num_prod_perf_req++;
3559 }
3560
3561 return 0;
3562}
3563
3564/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003565 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3566 * @hdd_ctx: Global HDD context
3567 * @tx_packets: Number of packets transmitted in the last sample period
3568 * @rx_packets: Number of packets received in the last sample period
3569 *
3570 * Return: 0 on success, negative errno on error
3571 */
3572int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3573 uint64_t rx_packets)
3574{
3575 int ret;
3576
3577 cds_ssr_protect(__func__);
3578 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3579 cds_ssr_unprotect(__func__);
3580
3581 return ret;
3582}
3583
3584/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003585 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3586 * @work: struct work_struct
3587 * @work_handler: work_handler
3588 *
3589 * Return: none
3590 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003591static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3592 work_func_t work_handler)
3593{
3594 INIT_WORK(work, work_handler);
3595}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003596
3597/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003598 * hdd_ipa_setup_rm() - Setup IPA resource management
3599 * @hdd_ipa: Global HDD IPA context
3600 *
3601 * Return: 0 on success, negative errno on error
3602 */
3603static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3604{
3605 struct ipa_rm_create_params create_params = { 0 };
3606 int ret;
3607
3608 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3609 return 0;
3610
Rajeev Kumar217f2172016-01-06 18:11:55 -08003611 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3612 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 memset(&create_params, 0, sizeof(create_params));
3614 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3615 create_params.reg_params.user_data = hdd_ipa;
3616 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3617 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3618
3619 ret = ipa_rm_create_resource(&create_params);
3620 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303621 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003622 "Create RM resource failed: %d", ret);
3623 goto setup_rm_fail;
3624 }
3625
3626 memset(&create_params, 0, sizeof(create_params));
3627 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3628 create_params.request_resource = hdd_ipa_rm_cons_request;
3629 create_params.release_resource = hdd_ipa_rm_cons_release;
3630 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3631
3632 ret = ipa_rm_create_resource(&create_params);
3633 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303634 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003635 "Create RM CONS resource failed: %d", ret);
3636 goto delete_prod;
3637 }
3638
3639 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3640 IPA_RM_RESOURCE_APPS_CONS);
3641
3642 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3643 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3644 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303645 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003646 ret);
3647 goto timer_init_failed;
3648 }
3649
3650 /* Set the lowest bandwidth to start with */
3651 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3652
3653 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303654 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003655 "Set perf level failed: %d", ret);
3656 goto set_perf_failed;
3657 }
3658
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303659 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003660 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3661 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303662 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003663 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3664 hdd_ipa->wake_lock_released = true;
3665 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3666
3667 return ret;
3668
3669set_perf_failed:
3670 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3671
3672timer_init_failed:
3673 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3674
3675delete_prod:
3676 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3677
3678setup_rm_fail:
3679 return ret;
3680}
3681
3682/**
3683 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3684 * @hdd_ipa: Global HDD IPA context
3685 *
3686 * Destroys all resources associated with the IPA resource manager
3687 *
3688 * Return: None
3689 */
3690static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3691{
3692 int ret;
3693
3694 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3695 return;
3696
3697 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303698 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003699
3700#ifdef WLAN_OPEN_SOURCE
3701 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
3702#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303703 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003704
3705 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3706
3707 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3708 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303709 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003710 "RM PROD resource delete failed %d", ret);
3711
3712 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3713 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303714 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003715 "RM CONS resource delete failed %d", ret);
3716}
3717
3718/**
3719 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3720 * @skb: network buffer
3721 * @adapter: network adapter
3722 *
3723 * Called when a network buffer is received which should not be routed
3724 * to the IPA module.
3725 *
3726 * Return: None
3727 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303728static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003729 hdd_adapter_t *adapter)
3730{
3731 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3732 unsigned int cpu_index;
3733
3734 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003735 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003736 adapter);
3737 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003738 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003739 return;
3740 }
3741
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003742 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003743 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003744 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745 return;
3746 }
3747
3748 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3749 skb->dev = adapter->dev;
3750 skb->protocol = eth_type_trans(skb, skb->dev);
3751 skb->ip_summed = CHECKSUM_NONE;
3752
3753 cpu_index = wlan_hdd_get_cpu();
3754
3755 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
3756 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
3757 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3758 else
3759 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3760
3761 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
3762 adapter->dev->last_rx = jiffies;
3763}
3764
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003765/**
Leo Chang69c39692016-10-12 20:11:12 -07003766 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3767 * @hdd_ipa: pointer to hdd ipa context
3768 * @adapter: network adapter
3769 * @skb: data pointer
3770 *
3771 * if exception packet has set forward bit, copied new packet should be
3772 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3773 * put into pm queue and tx procedure will be differed
3774 *
3775 * Return: None
3776 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003777static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
3778 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003779{
Leo Chang69c39692016-10-12 20:11:12 -07003780 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3781
Leo Chang69c39692016-10-12 20:11:12 -07003782 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
3783 /* WLAN subsystem is in suspend, put int queue */
3784 if (hdd_ipa->suspended) {
3785 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3786 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3787 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003788 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3789 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003790 pm_tx_cb->exception = true;
3791 pm_tx_cb->adapter = adapter;
3792 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003793 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003794 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3795 hdd_ipa->stats.num_tx_queued++;
3796 } else {
3797 /* Resume, put packet into WLAN TX */
3798 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003799 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003800 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3801 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003802 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003803 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003804 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003805 hdd_ipa->ipa_tx_forward++;
3806 }
3807 }
3808}
3809
3810/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003811 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3812 * @hdd_ipa: pointer to HDD IPA struct
3813 * @adapter: hdd adapter pointer
3814 * @desc: Firmware descriptor
3815 * @skb: Data buffer
3816 *
3817 * Return:
3818 * HDD_IPA_FORWARD_PKT_NONE
3819 * HDD_IPA_FORWARD_PKT_DISCARD
3820 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3821 *
3822 */
3823
3824static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3825 struct hdd_ipa_priv *hdd_ipa,
3826 hdd_adapter_t *adapter,
3827 uint8_t desc,
3828 qdf_nbuf_t skb)
3829{
3830 int ret = HDD_IPA_FORWARD_PKT_NONE;
3831
3832 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303833 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003834 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
3835 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303836 /* Drop the packet*/
3837 hdd_ipa->stats.num_tx_fwd_err++;
3838 kfree_skb(skb);
3839 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3840 return ret;
3841 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003842 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3843 "Forward packet to Tx (fw_desc=%d)", desc);
3844 hdd_ipa->ipa_tx_forward++;
3845
3846 if ((desc & FW_RX_DESC_DISCARD_M)) {
3847 hdd_ipa_forward(hdd_ipa, adapter, skb);
3848 hdd_ipa->ipa_rx_internel_drop_count++;
3849 hdd_ipa->ipa_rx_discard++;
3850 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3851 } else {
3852 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003853
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003854 if (cloned_skb)
3855 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3856 else
3857 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3858 "%s: tx skb alloc failed",
3859 __func__);
3860 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3861 }
3862 }
3863
3864 return ret;
3865}
3866
3867/**
Leo Chang69c39692016-10-12 20:11:12 -07003868 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003869 * @priv: pointer to private data registered with IPA (we register a
3870 * pointer to the global IPA context)
3871 * @evt: the IPA event which triggered the callback
3872 * @data: data associated with the event
3873 *
3874 * Return: None
3875 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003876static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003877 unsigned long data)
3878{
3879 struct hdd_ipa_priv *hdd_ipa = NULL;
3880 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303881 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003882 uint8_t iface_id;
3883 uint8_t session_id;
3884 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003885 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003886 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003887
3888 hdd_ipa = (struct hdd_ipa_priv *)priv;
3889
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003890 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3891 return;
3892
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003893 switch (evt) {
3894 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303895 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003896
3897 /*
3898 * When SSR is going on or driver is unloading,
3899 * just drop the packets.
3900 */
3901 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
3902 if (0 != status) {
3903 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3904 "Invalid context: drop packet");
3905 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3906 kfree_skb(skb);
3907 return;
3908 }
3909
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003910 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3911 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003912 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08003913 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003914 "IPA_RECEIVE: session_id=%u, iface_id=%u",
3915 session_id, iface_id);
3916 } else {
3917 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
3918 }
3919
3920 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303921 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003922 "IPA_RECEIVE: Invalid iface_id: %u",
3923 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003924 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003925 "w2i -- skb",
3926 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003928 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003929 return;
3930 }
3931
3932 iface_context = &hdd_ipa->iface_context[iface_id];
3933 adapter = iface_context->adapter;
3934
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303935 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003936 "w2i -- skb",
3937 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003938 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3939 hdd_ipa->stats.num_rx_excep++;
3940 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
3941 } else {
3942 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
3943 }
3944
3945 iface_context->stats.num_rx_ipa_excep++;
3946
3947 /* Disable to forward Intra-BSS Rx packets when
3948 * ap_isolate=1 in hostapd.conf
3949 */
Yun Park046101c2016-09-02 15:32:14 -07003950 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003951 /*
3952 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3953 * all Rx packets to IPA uC, which need to be forwarded
3954 * to other interface.
3955 * And, IPA driver will send back to WLAN host driver
3956 * through exception pipe with fw_desc field set by FW.
3957 * Here we are checking fw_desc field for FORWARD bit
3958 * set, and forward to Tx. Then copy to kernel stack
3959 * only when DISCARD bit is not set.
3960 */
3961 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003962 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3963 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3964 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003965 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003966 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003967 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003968 "Intra-BSS FWD is disabled-skip forward to Tx");
3969 }
3970
3971 hdd_ipa_send_skb_to_network(skb, adapter);
3972 break;
3973
3974 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303975 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003976 "w2i cb wrong event: 0x%x", evt);
3977 return;
3978 }
3979}
3980
3981/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003982 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3983 * @priv: pointer to private data registered with IPA (we register a
3984 * pointer to the global IPA context)
3985 * @evt: the IPA event which triggered the callback
3986 * @data: data associated with the event
3987 *
3988 * Return: None
3989 */
3990static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3991 unsigned long data)
3992{
3993 cds_ssr_protect(__func__);
3994 __hdd_ipa_w2i_cb(priv, evt, data);
3995 cds_ssr_unprotect(__func__);
3996}
3997
3998/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003999 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4000 * @skb: packet buffer which was transmitted
4001 *
4002 * Return: None
4003 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304004void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004005{
4006 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4007
Govind Singhb6a89772016-08-12 11:23:35 +05304008 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05304009 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004010 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304011 ipa_free_skb((struct ipa_rx_data *)
4012 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004013
4014 hdd_ipa->stats.num_tx_comp_cnt++;
4015
4016 atomic_dec(&hdd_ipa->tx_ref_cnt);
4017
4018 hdd_ipa_rm_try_release(hdd_ipa);
4019}
4020
4021/**
4022 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4023 * @iface_context: interface-specific IPA context
4024 * @ipa_tx_desc: packet data descriptor
4025 *
4026 * Return: None
4027 */
4028static void hdd_ipa_send_pkt_to_tl(
4029 struct hdd_ipa_iface_context *iface_context,
4030 struct ipa_rx_data *ipa_tx_desc)
4031{
4032 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004033 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304034 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004035
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304036 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004037 adapter = iface_context->adapter;
4038 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304039 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004040 ipa_free_skb(ipa_tx_desc);
4041 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304042 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004043 hdd_ipa_rm_try_release(hdd_ipa);
4044 return;
4045 }
4046
4047 /*
4048 * During CAC period, data packets shouldn't be sent over the air so
4049 * drop all the packets here
4050 */
4051 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4052 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304053 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004054 iface_context->stats.num_tx_cac_drop++;
4055 hdd_ipa_rm_try_release(hdd_ipa);
4056 return;
4057 }
4058
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004059 ++adapter->stats.tx_packets;
4060
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304061 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004062
4063 skb = ipa_tx_desc->skb;
4064
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304065 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304066 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004067 /* FIXME: This is broken. No such field in cb any more:
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08004068 * NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb;
4069 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004070 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304071 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004072 ipa_tx_desc->dma_addr
4073 + HDD_IPA_WLAN_FRAG_HEADER
4074 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004075 ipa_tx_desc->skb->len -=
4076 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4077 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304078 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004079
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004080 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304081 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004082
4083 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
4084
Leo Changfdb45c32016-10-28 11:09:23 -07004085 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004086 (struct cdp_vdev *)iface_context->tl_context,
4087 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004088 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304089 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004090 ipa_free_skb(ipa_tx_desc);
4091 iface_context->stats.num_tx_err++;
4092 hdd_ipa_rm_try_release(hdd_ipa);
4093 return;
4094 }
4095
4096 atomic_inc(&hdd_ipa->tx_ref_cnt);
4097
4098 iface_context->stats.num_tx++;
4099
4100}
4101
4102/**
Leo Chang11545d62016-10-17 14:53:50 -07004103 * hdd_ipa_is_present() - get IPA hw status
4104 * @hdd_ctx: pointer to hdd context
4105 *
4106 * ipa_uc_reg_rdyCB is not directly designed to check
4107 * ipa hw status. This is an undocumented function which
4108 * has confirmed with IPA team.
4109 *
4110 * Return: true - ipa hw present
4111 * false - ipa hw not present
4112 */
4113bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
4114{
4115 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004116 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004117 return true;
4118 else
4119 return false;
4120}
4121
4122/**
Leo Chang69c39692016-10-12 20:11:12 -07004123 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004124 * @work: pointer to the scheduled work
4125 *
4126 * Called during PM resume to send packets to TL which were queued
4127 * while host was in the process of suspending.
4128 *
4129 * Return: None
4130 */
Leo Chang69c39692016-10-12 20:11:12 -07004131static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004132{
4133 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4134 struct hdd_ipa_priv,
4135 pm_work);
4136 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304137 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004138 uint32_t dequeued = 0;
4139
Leo Chang69c39692016-10-12 20:11:12 -07004140 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4141 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304142 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304143 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4144 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304145 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146
4147 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004148 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004149 if (pm_tx_cb->exception) {
4150 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4151 "FLUSH EXCEPTION");
4152 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
4153 } else {
4154 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004155 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004156 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304157 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004158 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304159 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004160 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4161 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004162
4163 hdd_ipa->stats.num_tx_dequeued += dequeued;
4164 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4165 hdd_ipa->stats.num_max_pm_queue = dequeued;
4166}
4167
4168/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004169 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004170 * @priv: pointer to private data registered with IPA (we register a
4171 * pointer to the interface-specific IPA context)
4172 * @evt: the IPA event which triggered the callback
4173 * @data: data associated with the event
4174 *
4175 * Return: None
4176 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004177static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004178 unsigned long data)
4179{
4180 struct hdd_ipa_priv *hdd_ipa = NULL;
4181 struct ipa_rx_data *ipa_tx_desc;
4182 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304183 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004184 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304185 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004186
Mukul Sharma81661ae2015-10-30 20:26:02 +05304187 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004188 ipa_tx_desc = (struct ipa_rx_data *)data;
4189 hdd_ipa = iface_context->hdd_ipa;
4190
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004191 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004192 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4193 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004194 iface_context->stats.num_tx_drop++;
4195 return;
4196 }
4197
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004198 /*
4199 * When SSR is going on or driver is unloading, just drop the packets.
4200 * During SSR, there is no use in queueing the packets as STA has to
4201 * connect back any way
4202 */
4203 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304204 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004205 ipa_free_skb(ipa_tx_desc);
4206 iface_context->stats.num_tx_drop++;
4207 return;
4208 }
4209
4210 skb = ipa_tx_desc->skb;
4211
Yun Parkb187d542016-11-14 18:10:04 -08004212 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4213 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004214
4215 /*
4216 * If PROD resource is not requested here then there may be cases where
4217 * IPA hardware may be clocked down because of not having proper
4218 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4219 * workaround to request PROD resource while data is going over CONS
4220 * pipe to prevent the IPA hardware clockdown.
4221 */
4222 hdd_ipa_rm_request(hdd_ipa);
4223
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304224 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004225 /*
4226 * If host is still suspended then queue the packets and these will be
4227 * drained later when resume completes. When packet is arrived here and
4228 * host is suspended, this means that there is already resume is in
4229 * progress.
4230 */
4231 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304232 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004233 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4234 pm_tx_cb->iface_context = iface_context;
4235 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304236 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004237 hdd_ipa->stats.num_tx_queued++;
4238
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304239 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004240 return;
4241 }
4242
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304243 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004244
4245 /*
4246 * If we are here means, host is not suspended, wait for the work queue
4247 * to finish.
4248 */
4249#ifdef WLAN_OPEN_SOURCE
4250 flush_work(&hdd_ipa->pm_work);
4251#endif
4252
4253 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4254}
4255
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004256/*
4257 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4258 * @priv: pointer to private data registered with IPA (we register a
4259 * pointer to the interface-specific IPA context)
4260 * @evt: the IPA event which triggered the callback
4261 * @data: data associated with the event
4262 *
4263 * Return: None
4264 */
4265static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
4266 unsigned long data)
4267{
4268 cds_ssr_protect(__func__);
4269 __hdd_ipa_i2w_cb(priv, evt, data);
4270 cds_ssr_unprotect(__func__);
4271}
4272
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004273/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004274 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004275 * @hdd_ctx: Global HDD context
4276 *
4277 * Return: 0 on success, negativer errno on error
4278 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004279static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004281 struct hdd_ipa_priv *hdd_ipa;
4282
4283 if (wlan_hdd_validate_context(hdd_ctx))
4284 return 0;
4285
4286 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004287
4288 if (!hdd_ipa_is_enabled(hdd_ctx))
4289 return 0;
4290
4291 /*
4292 * Check if IPA is ready for suspend, If we are here means, there is
4293 * high chance that suspend would go through but just to avoid any race
4294 * condition after suspend started, these checks are conducted before
4295 * allowing to suspend.
4296 */
4297 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4298 return -EAGAIN;
4299
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304300 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004301
4302 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304303 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004304 return -EAGAIN;
4305 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304306 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004307
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304308 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004309 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304310 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004311
4312 return 0;
4313}
4314
4315/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004316 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4317 * @hdd_ctx: Global HDD context
4318 *
4319 * Return: 0 on success, negativer errno on error
4320 */
4321int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4322{
4323 int ret;
4324
4325 cds_ssr_protect(__func__);
4326 ret = __hdd_ipa_suspend(hdd_ctx);
4327 cds_ssr_unprotect(__func__);
4328
4329 return ret;
4330}
4331
4332/**
4333 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334 * hdd_ctx: Global HDD context
4335 *
4336 * Return: 0 on success, negative errno on error
4337 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004338static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004339{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004340 struct hdd_ipa_priv *hdd_ipa;
4341
4342 if (wlan_hdd_validate_context(hdd_ctx))
4343 return 0;
4344
4345 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004346
4347 if (!hdd_ipa_is_enabled(hdd_ctx))
4348 return 0;
4349
4350 schedule_work(&hdd_ipa->pm_work);
4351
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304352 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004353 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304354 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355
4356 return 0;
4357}
4358
4359/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004360 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4361 * hdd_ctx: Global HDD context
4362 *
4363 * Return: 0 on success, negative errno on error
4364 */
4365int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4366{
4367 int ret;
4368
4369 cds_ssr_protect(__func__);
4370 ret = __hdd_ipa_resume(hdd_ctx);
4371 cds_ssr_unprotect(__func__);
4372
4373 return ret;
4374}
4375
4376/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004377 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4378 * @hdd_ipa: Global HDD IPA context
4379 *
4380 * Return: 0 on success, negative errno on error
4381 */
4382static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4383{
4384 int i, ret = 0;
4385 struct ipa_sys_connect_params *ipa;
4386 uint32_t desc_fifo_sz;
4387
4388 /* The maximum number of descriptors that can be provided to a BAM at
4389 * once is one less than the total number of descriptors that the buffer
4390 * can contain.
4391 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4392 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4393 * be provided at once.
4394 * Because of above requirement, one extra descriptor will be added to
4395 * make sure hardware always has one descriptor.
4396 */
4397 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4398 + sizeof(struct sps_iovec);
4399
4400 /*setup TX pipes */
4401 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4402 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4403
4404 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4405 ipa->desc_fifo_sz = desc_fifo_sz;
4406 ipa->priv = &hdd_ipa->iface_context[i];
4407 ipa->notify = hdd_ipa_i2w_cb;
4408
4409 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4410 ipa->ipa_ep_cfg.hdr.hdr_len =
4411 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4412 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4413 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4414 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4415 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4416 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4417 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4418 } else {
4419 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4420 }
4421 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4422
4423 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4424 ipa->keep_ipa_awake = 1;
4425
4426 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4427 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004428 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4429 "Failed for pipe %d ret: %d", i, ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430 goto setup_sys_pipe_fail;
4431 }
4432 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4433 }
4434
4435 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4436 /*
4437 * Hard code it here, this can be extended if in case
4438 * PROD pipe is also per interface.
4439 * Right now there is no advantage of doing this.
4440 */
4441 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4442
4443 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4444
4445 ipa->client = hdd_ipa->prod_client;
4446
4447 ipa->desc_fifo_sz = desc_fifo_sz;
4448 ipa->priv = hdd_ipa;
4449 ipa->notify = hdd_ipa_w2i_cb;
4450
4451 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4452 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4453 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4454 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4455
4456 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4457 ipa->keep_ipa_awake = 1;
4458
4459 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4460 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304461 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004462 "Failed for RX pipe: %d", ret);
4463 goto setup_sys_pipe_fail;
4464 }
4465 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4466 }
4467
4468 return ret;
4469
4470setup_sys_pipe_fail:
4471
4472 while (--i >= 0) {
4473 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304474 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004475 sizeof(struct hdd_ipa_sys_pipe));
4476 }
4477
4478 return ret;
4479}
4480
4481/**
4482 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4483 * @hdd_ipa: Global HDD IPA context
4484 *
4485 * Return: None
4486 */
4487static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4488{
4489 int ret = 0, i;
4490 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4491 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4492 ret =
4493 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4494 conn_hdl);
4495 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304496 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004497 ret);
4498
4499 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4500 }
4501 }
4502}
4503
4504/**
4505 * hdd_ipa_register_interface() - register IPA interface
4506 * @hdd_ipa: Global IPA context
4507 * @iface_context: Per-interface IPA context
4508 *
4509 * Return: 0 on success, negative errno on error
4510 */
4511static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
4512 struct hdd_ipa_iface_context
4513 *iface_context)
4514{
4515 struct ipa_tx_intf tx_intf;
4516 struct ipa_rx_intf rx_intf;
4517 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
4518 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
4519 char *ifname = iface_context->adapter->dev->name;
4520
4521 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
4522 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
4523
4524 int num_prop = 1;
4525 int ret = 0;
4526
4527 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
4528 num_prop++;
4529
4530 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
4531 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304532 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004533 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304534 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004535 goto register_interface_fail;
4536 }
4537
4538 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
4539 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304540 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004541 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304542 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004543 goto register_interface_fail;
4544 }
4545
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304546 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
4547 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004548
4549 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4550 ifname, HDD_IPA_IPV4_NAME_EXT);
4551 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4552 ifname, HDD_IPA_IPV6_NAME_EXT);
4553
4554 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4555 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
4556 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4557 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4558
4559 /*
4560 * Interface ID is 3rd byte in the CLD header. Add the meta data and
4561 * mask to identify the interface in IPA hardware
4562 */
4563 rx_prop[IPA_IP_v4].attrib.meta_data =
4564 htonl(iface_context->adapter->sessionId << 16);
4565 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4566
4567 rx_intf.num_props++;
4568 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4569 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4570 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
4571 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4572 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4573 rx_prop[IPA_IP_v4].attrib.meta_data =
4574 htonl(iface_context->adapter->sessionId << 16);
4575 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4576
4577 rx_intf.num_props++;
4578 }
4579
4580 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4581 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4582 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4583 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
4584 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
4585 IPA_RESOURCE_NAME_MAX);
4586 tx_intf.num_props++;
4587
4588 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4589 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4590 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4591 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4592 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
4593 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
4594 IPA_RESOURCE_NAME_MAX);
4595 tx_intf.num_props++;
4596 }
4597
4598 tx_intf.prop = tx_prop;
4599 rx_intf.prop = rx_prop;
4600
4601 /* Call the ipa api to register interface */
4602 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
4603
4604register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304605 qdf_mem_free(tx_prop);
4606 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004607 return ret;
4608}
4609
4610/**
4611 * hdd_remove_ipa_header() - Remove a specific header from IPA
4612 * @name: Name of the header to be removed
4613 *
4614 * Return: None
4615 */
4616static void hdd_ipa_remove_header(char *name)
4617{
4618 struct ipa_ioc_get_hdr hdrlookup;
4619 int ret = 0, len;
4620 struct ipa_ioc_del_hdr *ipa_hdr;
4621
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304622 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
4624 ret = ipa_get_hdr(&hdrlookup);
4625 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004626 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004627 name, ret);
4628 return;
4629 }
4630
Srinivas Girigowda97852372017-03-06 16:52:59 -08004631 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004632 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304633 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304635 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004636 return;
4637 }
4638 ipa_hdr->num_hdls = 1;
4639 ipa_hdr->commit = 0;
4640 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
4641 ipa_hdr->hdl[0].status = -1;
4642 ret = ipa_del_hdr(ipa_hdr);
4643 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304644 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004645 ret);
4646
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304647 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004648}
4649
4650/**
Yun Parkb187d542016-11-14 18:10:04 -08004651 * wlan_ipa_add_hdr() - Add IPA Tx header
4652 * @ipa_hdr: pointer to IPA header addition parameters
4653 *
4654 * Call IPA API to add IPA Tx header descriptor
4655 * and dump Tx header struct
4656 *
4657 * Return: 0 for success, non-zero for failure
4658 */
4659static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
4660{
4661 int ret;
4662
Srinivas Girigowda97852372017-03-06 16:52:59 -08004663 hdd_debug("==== IPA Tx Header ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08004664 "name: %s\n"
4665 "hdr_len: %d\n"
4666 "type: %d\n"
4667 "is_partial: %d\n"
4668 "hdr_hdl: 0x%x\n"
4669 "status: %d\n"
4670 "is_eth2_ofst_valid: %d\n"
4671 "eth2_ofst: %d\n",
4672 ipa_hdr->hdr[0].name,
4673 ipa_hdr->hdr[0].hdr_len,
4674 ipa_hdr->hdr[0].type,
4675 ipa_hdr->hdr[0].is_partial,
4676 ipa_hdr->hdr[0].hdr_hdl,
4677 ipa_hdr->hdr[0].status,
4678 ipa_hdr->hdr[0].is_eth2_ofst_valid,
4679 ipa_hdr->hdr[0].eth2_ofst);
4680
4681 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:",
4682 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4683
4684 ret = ipa_add_hdr(ipa_hdr);
4685 return ret;
4686}
4687
4688/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004689 * hdd_ipa_add_header_info() - Add IPA header for a given interface
4690 * @hdd_ipa: Global HDD IPA context
4691 * @iface_context: Interface-specific HDD IPA context
4692 * @mac_addr: Interface MAC address
4693 *
4694 * Return: 0 on success, negativer errno value on error
4695 */
4696static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
4697 struct hdd_ipa_iface_context *iface_context,
4698 uint8_t *mac_addr)
4699{
4700 hdd_adapter_t *adapter = iface_context->adapter;
4701 char *ifname;
4702 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
4703 int ret = -EINVAL;
4704 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
4705 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
4706
4707 ifname = adapter->dev->name;
4708
Srinivas Girigowda97852372017-03-06 16:52:59 -08004709 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004710 ifname, mac_addr);
4711
4712 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304713 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004714 + sizeof(struct ipa_hdr_add));
4715 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304716 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004717 "%s: ipa_hdr allocation failed", ifname);
4718 ret = -ENOMEM;
4719 goto end;
4720 }
4721
4722 ipa_hdr->commit = 0;
4723 ipa_hdr->num_hdrs = 1;
4724
4725 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4726 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4727 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4728 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4729 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304730 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004731 "ifname=%s, vdev_id=%d",
4732 ifname, uc_tx_hdr->ipa_hd.vdev_id);
4733 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4734 ifname, HDD_IPA_IPV4_NAME_EXT);
4735 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
4736 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
4737 ipa_hdr->hdr[0].is_partial = 1;
4738 ipa_hdr->hdr[0].hdr_hdl = 0;
4739 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4740 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4741
Yun Parkb187d542016-11-14 18:10:04 -08004742 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004743 } else {
4744 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4745
4746 /* Set the Source MAC */
4747 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
4748 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4749
4750 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4751 ifname, HDD_IPA_IPV4_NAME_EXT);
4752 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4753 ipa_hdr->hdr[0].is_partial = 1;
4754 ipa_hdr->hdr[0].hdr_hdl = 0;
4755 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4756 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4757
4758 /* Set the type to IPV4 in the header */
4759 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
4760
4761 ret = ipa_add_hdr(ipa_hdr);
4762 }
4763 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304764 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004765 ifname, ret);
4766 goto end;
4767 }
4768
Srinivas Girigowda97852372017-03-06 16:52:59 -08004769 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004770 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4771
4772 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4773 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4774 ifname, HDD_IPA_IPV6_NAME_EXT);
4775
4776 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4777 uc_tx_hdr =
4778 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4779 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004780 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004781 } else {
4782 /* Set the type to IPV6 in the header */
4783 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4784 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004785 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004786 }
4787
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004788 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304789 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004790 "%s: IPv6 add hdr failed: %d", ifname, ret);
4791 goto clean_ipv4_hdr;
4792 }
4793
Srinivas Girigowda97852372017-03-06 16:52:59 -08004794 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004795 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4796 }
4797
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304798 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004799
4800 return ret;
4801
4802clean_ipv4_hdr:
4803 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4804 ifname, HDD_IPA_IPV4_NAME_EXT);
4805 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
4806end:
4807 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304808 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004809
4810 return ret;
4811}
4812
4813/**
4814 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
4815 * @adapter: Adapter upon which IPA was previously configured
4816 *
4817 * Return: None
4818 */
4819static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
4820{
4821 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4822 int ret;
4823 char name_ipa[IPA_RESOURCE_NAME_MAX];
4824
4825 /* Remove the headers */
4826 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4827 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
4828 hdd_ipa_remove_header(name_ipa);
4829
4830 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4831 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4832 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
4833 hdd_ipa_remove_header(name_ipa);
4834 }
4835 /* unregister the interface with IPA */
4836 ret = ipa_deregister_intf(adapter->dev->name);
4837 if (ret)
Srinivas Girigowda97852372017-03-06 16:52:59 -08004838 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004839 "%s: ipa_deregister_intf fail: %d",
4840 adapter->dev->name, ret);
4841}
4842
4843/**
4844 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4845 * @iface_context: interface-specific IPA context
4846 *
4847 * Return: None
4848 */
4849static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4850{
4851 if (iface_context == NULL)
4852 return;
4853
4854 hdd_ipa_clean_hdr(iface_context->adapter);
4855
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304856 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004857 iface_context->adapter->ipa_context = NULL;
4858 iface_context->adapter = NULL;
4859 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304860 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004861 iface_context->ifa_address = 0;
4862 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304863 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004864 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304865 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004866 }
4867 iface_context->hdd_ipa->num_iface--;
4868}
4869
4870/**
4871 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4872 * @hdd_ipa: HDD IPA global context
4873 * @adapter: Interface upon which IPA is being setup
4874 * @sta_id: Station ID of the API instance
4875 *
4876 * Return: 0 on success, negative errno value on error
4877 */
4878static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
4879 hdd_adapter_t *adapter, uint8_t sta_id)
4880{
4881 struct hdd_ipa_iface_context *iface_context = NULL;
4882 void *tl_context = NULL;
4883 int i, ret = 0;
4884
4885 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4886 * channel change indication. Since these indications are sent by lower
4887 * layer as SAP updates and IPA doesn't have to do anything for these
4888 * updates so ignoring!
4889 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004890 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004891 return 0;
4892
4893 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4894 if (hdd_ipa->iface_context[i].adapter == NULL) {
4895 iface_context = &(hdd_ipa->iface_context[i]);
4896 break;
4897 }
4898 }
4899
4900 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304901 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004902 "All the IPA interfaces are in use");
4903 ret = -ENOMEM;
4904 goto end;
4905 }
4906
4907 adapter->ipa_context = iface_context;
4908 iface_context->adapter = adapter;
4909 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004910 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07004911 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004912 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304913 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004914 "Not able to get TL context sta_id: %d", sta_id);
4915 ret = -EINVAL;
4916 goto end;
4917 }
4918
4919 iface_context->tl_context = tl_context;
4920
4921 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
4922 adapter->dev->dev_addr);
4923
4924 if (ret)
4925 goto end;
4926
4927 /* Configure the TX and RX pipes filter rules */
4928 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
4929 if (ret)
4930 goto cleanup_header;
4931
4932 hdd_ipa->num_iface++;
4933 return ret;
4934
4935cleanup_header:
4936
4937 hdd_ipa_clean_hdr(adapter);
4938end:
4939 if (iface_context)
4940 hdd_ipa_cleanup_iface(iface_context);
4941 return ret;
4942}
4943
Yun Parka27049a2016-10-11 12:30:49 -07004944#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004945/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004946 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004947 * @mcc_mode: 0=MCC/1=SCC
4948 *
4949 * Return: 0 on success, negative errno value on error
4950 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004951static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004952{
4953 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304954 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004955 hdd_adapter_t *pAdapter;
4956 struct ipa_msg_meta meta;
4957 struct ipa_wlan_msg *msg;
4958 int ret;
4959
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004960 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004961 return -EINVAL;
4962
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004963 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4964 return -EINVAL;
4965
4966 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004967 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004968 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304969 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004970 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08004971 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004972 pAdapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004973 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004974 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004975 hdd_deinit_tx_rx(pAdapter);
4976 }
4977 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004978 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004979 adapter_node = next;
4980 }
4981 }
4982
4983 /* Send SCC/MCC Switching event to IPA */
4984 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304985 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004986 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004987 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004988 return -ENOMEM;
4989 }
4990
4991 meta.msg_type = mcc_mode ?
4992 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Srinivas Girigowda97852372017-03-06 16:52:59 -08004993 hdd_debug("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004994
4995 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4996
4997 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004998 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305000 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005001 }
5002
5003 return ret;
5004}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005005
5006/**
5007 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5008 * @mcc_mode: 0=MCC/1=SCC
5009 *
5010 * Return: 0 on success, negative errno value on error
5011 */
5012int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
5013{
5014 int ret;
5015
5016 cds_ssr_protect(__func__);
5017 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5018 cds_ssr_unprotect(__func__);
5019
5020 return ret;
5021}
Yun Parka27049a2016-10-11 12:30:49 -07005022#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005023
5024/**
5025 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
5026 * @event: IPA WLAN event to be converted to a string
5027 *
5028 * Return: ASCII string representing the IPA WLAN event
5029 */
5030static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
5031{
5032 switch (event) {
5033 case WLAN_CLIENT_CONNECT:
5034 return "WLAN_CLIENT_CONNECT";
5035 case WLAN_CLIENT_DISCONNECT:
5036 return "WLAN_CLIENT_DISCONNECT";
5037 case WLAN_CLIENT_POWER_SAVE_MODE:
5038 return "WLAN_CLIENT_POWER_SAVE_MODE";
5039 case WLAN_CLIENT_NORMAL_MODE:
5040 return "WLAN_CLIENT_NORMAL_MODE";
5041 case SW_ROUTING_ENABLE:
5042 return "SW_ROUTING_ENABLE";
5043 case SW_ROUTING_DISABLE:
5044 return "SW_ROUTING_DISABLE";
5045 case WLAN_AP_CONNECT:
5046 return "WLAN_AP_CONNECT";
5047 case WLAN_AP_DISCONNECT:
5048 return "WLAN_AP_DISCONNECT";
5049 case WLAN_STA_CONNECT:
5050 return "WLAN_STA_CONNECT";
5051 case WLAN_STA_DISCONNECT:
5052 return "WLAN_STA_DISCONNECT";
5053 case WLAN_CLIENT_CONNECT_EX:
5054 return "WLAN_CLIENT_CONNECT_EX";
5055
5056 case IPA_WLAN_EVENT_MAX:
5057 default:
5058 return "UNKNOWN";
5059 }
5060}
5061
5062/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005063 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5064 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5065 *
5066 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
5067 */
5068static enum ipa_wlan_event
5069hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5070{
5071 enum ipa_wlan_event ipa_event;
5072
5073 switch (hdd_ipa_event_type) {
5074 case HDD_IPA_CLIENT_CONNECT:
5075 ipa_event = WLAN_CLIENT_CONNECT;
5076 break;
5077 case HDD_IPA_CLIENT_DISCONNECT:
5078 ipa_event = WLAN_CLIENT_DISCONNECT;
5079 break;
5080 case HDD_IPA_AP_CONNECT:
5081 ipa_event = WLAN_AP_CONNECT;
5082 break;
5083 case HDD_IPA_AP_DISCONNECT:
5084 ipa_event = WLAN_AP_DISCONNECT;
5085 break;
5086 case HDD_IPA_STA_CONNECT:
5087 ipa_event = WLAN_STA_CONNECT;
5088 break;
5089 case HDD_IPA_STA_DISCONNECT:
5090 ipa_event = WLAN_STA_DISCONNECT;
5091 break;
5092 case HDD_IPA_CLIENT_CONNECT_EX:
5093 ipa_event = WLAN_CLIENT_CONNECT_EX;
5094 break;
5095 case HDD_IPA_WLAN_EVENT_MAX:
5096 default:
5097 ipa_event = IPA_WLAN_EVENT_MAX;
5098 break;
5099 }
5100 return ipa_event;
5101
5102}
5103
5104/**
5105 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005106 * @adapter: adapter upon which the event was received
5107 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005108 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005109 * @mac_address: MAC address associated with the event
5110 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005111 * This function is meant to be called from within wlan_hdd_ipa.c
5112 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005113 * Return: 0 on success, negative errno value on error
5114 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07005115static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005116 enum ipa_wlan_event type, uint8_t *mac_addr)
5117{
5118 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5119 struct ipa_msg_meta meta;
5120 struct ipa_wlan_msg *msg;
5121 struct ipa_wlan_msg_ex *msg_ex = NULL;
5122 int ret;
5123
Srinivas Girigowda97852372017-03-06 16:52:59 -08005124 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005125 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5126 mac_addr, sta_id);
5127
5128 if (type >= IPA_WLAN_EVENT_MAX)
5129 return -EINVAL;
5130
5131 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5132 return -EINVAL;
5133
5134 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305135 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005136 return -EINVAL;
5137 }
5138
5139 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5140 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005141 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005142 return 0;
5143 }
5144
5145 /*
5146 * During IPA UC resource loading/unloading new events can be issued.
5147 * Store the events separately and handle them later.
5148 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005149 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5150 if (hdd_ipa->resource_loading) {
5151 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005152 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005153
Yun Park64c405e2017-01-10 22:35:51 -08005154 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5155 "IPA resource load in progress");
Yun Park7c4f31b2016-11-30 10:09:21 -08005156
Yun Park64c405e2017-01-10 22:35:51 -08005157 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005158
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005159 pending_event_count =
5160 qdf_list_size(&hdd_ipa->pending_event);
5161 if (pending_event_count >=
5162 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005163 hdd_debug("Reached max pending event count");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005164 qdf_list_remove_front(&hdd_ipa->pending_event,
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005165 (qdf_list_node_t **)&pending_event);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005166 } else {
5167 pending_event =
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005168 qdf_mem_malloc(sizeof(*pending_event));
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005169 }
5170
5171 if (!pending_event) {
Yun Park64c405e2017-01-10 22:35:51 -08005172 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park7c4f31b2016-11-30 10:09:21 -08005173 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5174 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005175 return -ENOMEM;
5176 }
5177
5178 pending_event->adapter = adapter;
5179 pending_event->sta_id = sta_id;
5180 pending_event->type = type;
5181 qdf_mem_copy(pending_event->mac_addr,
5182 mac_addr,
5183 QDF_MAC_ADDR_SIZE);
5184 qdf_list_insert_back(&hdd_ipa->pending_event,
5185 &pending_event->node);
5186
Yun Park64c405e2017-01-10 22:35:51 -08005187 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005188 return 0;
5189 } else if (hdd_ipa->resource_unloading) {
Yun Park64c405e2017-01-10 22:35:51 -08005190 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5191 "IPA resource unload in progress");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005192 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005193 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005194 }
5195
5196 hdd_ipa->stats.event[type]++;
5197
Leo Chang3bc8fed2015-11-13 10:59:47 -08005198 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005199 switch (type) {
5200 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005201 qdf_mutex_acquire(&hdd_ipa->event_lock);
5202
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005203 /* STA already connected and without disconnect, connect again
5204 * This is Roaming scenario
5205 */
5206 if (hdd_ipa->sta_connected)
5207 hdd_ipa_cleanup_iface(adapter->ipa_context);
5208
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005209 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5210 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305211 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005212 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005213 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005214
Yun Park8f289c82016-10-18 16:38:21 -07005215 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5216 (hdd_ipa->sap_num_connected_sta > 0) &&
5217 !hdd_ipa->sta_connected) {
5218 qdf_mutex_release(&hdd_ipa->event_lock);
5219 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005220 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005221 qdf_mutex_acquire(&hdd_ipa->event_lock);
5222 }
5223
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005224 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005225 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005226 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005227
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005228 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005229
5230 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005231 break;
5232
5233 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005234 qdf_mutex_acquire(&hdd_ipa->event_lock);
5235
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005236 /* For DFS channel we get two start_bss event (before and after
5237 * CAC). Also when ACS range includes both DFS and non DFS
5238 * channels, we could possibly change channel many times due to
5239 * RADAR detection and chosen channel may not be a DFS channels.
5240 * So dont return error here. Just discard the event.
5241 */
Yun Park8f289c82016-10-18 16:38:21 -07005242 if (adapter->ipa_context) {
5243 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005244 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005245 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005246
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005247 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5248 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005249 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005250 hdd_err("%s: Evt: %d, Interface setup failed",
5251 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005252 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005253 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005254
Yun Park8f289c82016-10-18 16:38:21 -07005255 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5256 qdf_mutex_release(&hdd_ipa->event_lock);
5257 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005258 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005259 qdf_mutex_acquire(&hdd_ipa->event_lock);
5260 }
5261
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005262 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005263 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005264 (adapter->ipa_context))->iface_id;
5265
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305266 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005267 break;
5268
5269 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305270 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005271
5272 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005273 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005274 hdd_err("%s: Evt: %d, STA already disconnected",
5275 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005276 return -EINVAL;
5277 }
Yun Parka37592b2016-06-11 17:10:28 -07005278
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005279 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005280
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005281 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005282 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005283 msg_ex->name);
5284 } else {
5285 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005286 if (!hdd_ipa->num_iface &&
5287 (HDD_IPA_UC_NUM_WDI_PIPE ==
5288 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005289 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005290 }
5291
Yun Park74127cf2016-09-18 11:22:41 -07005292 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5293 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005294 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005295 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005296 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005297 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005298 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5299 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005300 }
5301
Yun Park8f289c82016-10-18 16:38:21 -07005302 hdd_ipa_cleanup_iface(adapter->ipa_context);
5303
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305304 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005305 break;
5306
5307 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005308 qdf_mutex_acquire(&hdd_ipa->event_lock);
5309
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005310 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005311 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005312 hdd_err("%s: Evt: %d, SAP already disconnected",
5313 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005314 return -EINVAL;
5315 }
5316
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005317 if ((!hdd_ipa->num_iface) &&
5318 (HDD_IPA_UC_NUM_WDI_PIPE ==
5319 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005320 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005321 /*
5322 * We disable WDI pipes directly here since
5323 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5324 * processed when unloading WLAN driver is in
5325 * progress
5326 */
5327 hdd_ipa_uc_disable_pipes(hdd_ipa);
5328 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305329 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005330 "NO INTF left but still pipe clean up");
5331 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5332 }
5333 }
5334
5335 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005336 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005337 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005338 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005339 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005340 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5341 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005342 }
Yun Parka37592b2016-06-11 17:10:28 -07005343
Yun Park8f289c82016-10-18 16:38:21 -07005344 hdd_ipa_cleanup_iface(adapter->ipa_context);
5345
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305346 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005347 break;
5348
5349 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005350 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005351 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005352 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305353 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005354 return 0;
5355 }
5356
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305357 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005358 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5359 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005360 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305361 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005362 "%s: STA ID %d found, not valid",
5363 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005364 return 0;
5365 }
Yun Park312f71a2015-12-08 10:22:42 -08005366
5367 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005368 if (hdd_ipa->sap_num_connected_sta == 0 &&
5369 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005370 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005371 hdd_ipa->sta_connected) {
5372 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005373 hdd_ipa_uc_offload_enable_disable(
5374 hdd_get_adapter(hdd_ipa->hdd_ctx,
5375 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005376 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005377 qdf_mutex_acquire(&hdd_ipa->event_lock);
5378 }
Yun Parka37592b2016-06-11 17:10:28 -07005379
Yun Park312f71a2015-12-08 10:22:42 -08005380 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5381 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305382 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005383 "%s: handle 1st con ret %d",
5384 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005385
5386 if (hdd_ipa_uc_sta_is_enabled(
5387 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005388 hdd_ipa->sta_connected) {
5389 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005390 hdd_ipa_uc_offload_enable_disable(
5391 hdd_get_adapter(
5392 hdd_ipa->hdd_ctx,
5393 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005394 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005395 } else {
5396 qdf_mutex_release(&hdd_ipa->event_lock);
5397 }
Yun Parka37592b2016-06-11 17:10:28 -07005398
Yun Park312f71a2015-12-08 10:22:42 -08005399 return ret;
5400 }
5401 }
5402
5403 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005404
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305405 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005406
5407 meta.msg_type = type;
5408 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5409 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305410 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005411
5412 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305413 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005414 "msg_ex allocation failed");
5415 return -ENOMEM;
5416 }
5417 strlcpy(msg_ex->name, adapter->dev->name,
5418 IPA_RESOURCE_NAME_MAX);
5419 msg_ex->num_of_attribs = 1;
5420 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5421 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5422 msg_ex->attribs[0].offset =
5423 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5424 } else {
5425 msg_ex->attribs[0].offset =
5426 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5427 }
5428 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5429 IPA_MAC_ADDR_SIZE);
5430
5431 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5432
5433 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005434 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305435 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305436 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005437 return ret;
5438 }
5439 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005440 return ret;
5441
5442 case WLAN_CLIENT_DISCONNECT:
5443 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005444 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005445 "%s: IPA UC OFFLOAD NOT ENABLED",
5446 msg_ex->name);
5447 return 0;
5448 }
5449
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305450 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005451 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005452 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305453 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005454 "%s: STA ID %d NOT found, not valid",
5455 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005456 return 0;
5457 }
5458 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005459
Yun Park9b5030f2016-11-08 12:02:37 -08005460 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005461 if (!hdd_ipa->sap_num_connected_sta &&
5462 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005463 if ((false == hdd_ipa->resource_unloading)
5464 && (HDD_IPA_UC_NUM_WDI_PIPE ==
5465 hdd_ipa->activated_fw_pipe)) {
5466 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5467 }
5468
Yun Park8f289c82016-10-18 16:38:21 -07005469 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005470
5471 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5472 hdd_ipa->sta_connected)
5473 hdd_ipa_uc_offload_enable_disable(
5474 hdd_get_adapter(hdd_ipa->hdd_ctx,
5475 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005476 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005477 } else {
5478 qdf_mutex_release(&hdd_ipa->event_lock);
5479 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005480 break;
5481
5482 default:
5483 return 0;
5484 }
5485
5486 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305487 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005488 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305489 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005490 return -ENOMEM;
5491 }
5492
5493 meta.msg_type = type;
5494 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5495 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5496
Srinivas Girigowda97852372017-03-06 16:52:59 -08005497 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005498 msg->name, meta.msg_type);
5499
5500 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5501
5502 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005503 hdd_err("%s: Evt: %d fail:%d",
5504 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305505 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005506 return ret;
5507 }
5508
5509 hdd_ipa->stats.num_send_msg++;
5510
5511end:
5512 return ret;
5513}
5514
5515/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005516 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005517 * @adapter: adapter upon which the event was received
5518 * @sta_id: station id for the event
5519 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5520 * @mac_address: MAC address associated with the event
5521 *
5522 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5523 *
5524 * Return: 0 on success, negative errno value on error
5525 */
5526int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
5527 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5528{
5529 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005530 int ret = 0;
5531
5532 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005533
Leo Changa202b522016-10-14 16:13:50 -07005534 /* Data path offload only support for STA and SAP mode */
5535 if ((QDF_STA_MODE == adapter->device_mode) ||
5536 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005537 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005538
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005539 cds_ssr_unprotect(__func__);
5540
5541 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005542}
5543
5544/**
5545 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5546 * @hdd_ipa: Global HDD IPA context
5547 *
5548 * Return: None
5549 */
5550static void
5551hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5552{
5553 unsigned int pending_event_count;
5554 struct ipa_uc_pending_event *pending_event = NULL;
5555
5556 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005557 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005558 "%s, Pending Event Count %d", __func__, pending_event_count);
5559 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005560 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005561 "%s, No Pending Event", __func__);
5562 return;
5563 }
5564
5565 qdf_list_remove_front(&hdd_ipa->pending_event,
5566 (qdf_list_node_t **)&pending_event);
5567 while (pending_event != NULL) {
5568 __hdd_ipa_wlan_evt(pending_event->adapter,
5569 pending_event->type,
5570 pending_event->sta_id,
5571 pending_event->mac_addr);
5572 qdf_mem_free(pending_event);
5573 pending_event = NULL;
5574 qdf_list_remove_front(&hdd_ipa->pending_event,
5575 (qdf_list_node_t **)&pending_event);
5576 }
5577}
5578
5579/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005580 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5581 * @state: IPA RM state value
5582 *
5583 * Return: ASCII string representing the IPA RM state
5584 */
5585static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5586{
5587 switch (state) {
5588 case HDD_IPA_RM_RELEASED:
5589 return "RELEASED";
5590 case HDD_IPA_RM_GRANT_PENDING:
5591 return "GRANT_PENDING";
5592 case HDD_IPA_RM_GRANTED:
5593 return "GRANTED";
5594 }
5595
5596 return "UNKNOWN";
5597}
5598
5599/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005600 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005601 * @hdd_ctx: HDD global context
5602 *
5603 * Allocate hdd_ipa resources, ipa pipe resource and register
5604 * wlan interface with IPA module.
5605 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305606 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005607 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005608static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005609{
5610 struct hdd_ipa_priv *hdd_ipa = NULL;
5611 int ret, i;
5612 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005613 struct ol_txrx_pdev_t *pdev = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005614
5615 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305616 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005617
Yun Parkbaa62862017-01-18 13:43:34 -08005618 ENTER();
5619
5620 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005621 if (!pdev) {
5622 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5623 goto fail_return;
5624 }
5625
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305626 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005627 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305628 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005629 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005630 }
5631
5632 hdd_ctx->hdd_ipa = hdd_ipa;
5633 ghdd_ipa = hdd_ipa;
5634 hdd_ipa->hdd_ctx = hdd_ctx;
5635 hdd_ipa->num_iface = 0;
5636
5637 /* Create the interface context */
5638 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5639 iface_context = &hdd_ipa->iface_context[i];
5640 iface_context->hdd_ipa = hdd_ipa;
5641 iface_context->cons_client =
5642 hdd_ipa_adapter_2_client[i].cons_client;
5643 iface_context->prod_client =
5644 hdd_ipa_adapter_2_client[i].prod_client;
5645 iface_context->iface_id = i;
5646 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305647 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005648 }
5649 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005650 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5651 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005652 }
5653
Leo Chang69c39692016-10-12 20:11:12 -07005654 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305655 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305656 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005657
5658 ret = hdd_ipa_setup_rm(hdd_ipa);
5659 if (ret)
5660 goto fail_setup_rm;
5661
5662 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5663 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305664 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005665 hdd_ipa->sap_num_connected_sta = 0;
5666 hdd_ipa->ipa_tx_packets_diff = 0;
5667 hdd_ipa->ipa_rx_packets_diff = 0;
5668 hdd_ipa->ipa_p_tx_packets = 0;
5669 hdd_ipa->ipa_p_rx_packets = 0;
5670 hdd_ipa->resource_loading = false;
5671 hdd_ipa->resource_unloading = false;
5672 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005673 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08005674 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005675 /* Setup IPA sys_pipe for MCC */
5676 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5677 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5678 if (ret)
5679 goto fail_create_sys_pipe;
5680 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005681 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5682 goto fail_create_sys_pipe;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005683 } else {
5684 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5685 if (ret)
5686 goto fail_create_sys_pipe;
5687 }
5688
Yun Parkbaa62862017-01-18 13:43:34 -08005689 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305690 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005691
5692fail_create_sys_pipe:
5693 hdd_ipa_destroy_rm_resource(hdd_ipa);
5694fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305695 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305696 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005697 hdd_ctx->hdd_ipa = NULL;
5698 ghdd_ipa = NULL;
5699fail_return:
Yun Parkbaa62862017-01-18 13:43:34 -08005700 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305701 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005702}
5703
5704/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005705 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5706 * @hdd_ctx: HDD global context
5707 *
5708 * Allocate hdd_ipa resources, ipa pipe resource and register
5709 * wlan interface with IPA module.
5710 *
5711 * Return: QDF_STATUS enumeration
5712 */
5713QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
5714{
5715 QDF_STATUS ret;
5716
5717 cds_ssr_protect(__func__);
5718 ret = __hdd_ipa_init(hdd_ctx);
5719 cds_ssr_unprotect(__func__);
5720
5721 return ret;
5722}
5723
Arun Khandavallicc544b32017-01-30 19:52:16 +05305724
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005725/**
Yun Parkf19e07d2015-11-20 11:34:27 -08005726 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
5727 * @hdd_ipa: pointer to HDD IPA struct
5728 *
5729 * Return: none
5730 */
Jeff Johnsond7720632016-10-05 16:04:32 -07005731static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08005732{
5733 struct ipa_uc_pending_event *pending_event = NULL;
5734
Anurag Chouhanffb21542016-02-17 14:33:03 +05305735 while (qdf_list_remove_front(&hdd_ipa->pending_event,
5736 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305737 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005738 }
5739
Anurag Chouhanffb21542016-02-17 14:33:03 +05305740 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005741}
5742
5743/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005744 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005745 * @hdd_ctx: HDD global context
5746 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305747 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005748 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005749static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005750{
5751 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5752 int i;
5753 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305754 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005755 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5756
5757 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305758 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005759
5760 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5761 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5762 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5763 }
5764
5765 /* Teardown IPA sys_pipe for MCC */
5766 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5767 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5768
5769 hdd_ipa_destroy_rm_resource(hdd_ipa);
5770
5771#ifdef WLAN_OPEN_SOURCE
5772 cancel_work_sync(&hdd_ipa->pm_work);
5773#endif
5774
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305775 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005776
Nirav Shahcbc6d722016-03-01 16:24:53 +05305777 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5778 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305779 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005780
5781 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
5782 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
5783
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305784 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005785 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305786 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005787
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305788 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005789
5790 /* destory the interface lock */
5791 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5792 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305793 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005794 }
5795
5796 /* This should never hit but still make sure that there are no pending
5797 * descriptor in IPA hardware
5798 */
5799 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305800 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005801 "IPA Pending write done: %d Waiting!",
5802 hdd_ipa->pending_hw_desc_cnt);
5803
5804 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
5805 usleep_range(100, 100);
5806 }
5807
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305808 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005809 "IPA Pending write done: desc: %d %s(%d)!",
5810 hdd_ipa->pending_hw_desc_cnt,
5811 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
5812 : "leak", i);
5813 }
5814 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08005815 if (ipa_uc_dereg_rdyCB())
5816 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5817 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005818 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005819 if (true == hdd_ipa->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005820 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Govind Singh0487bf22016-08-24 23:08:57 +05305821 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
5822 __func__, hdd_ipa->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005823 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005824 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Govind Singh0487bf22016-08-24 23:08:57 +05305825 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
5826 __func__, hdd_ipa->rx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005827 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
5828 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305829 qdf_mutex_destroy(&hdd_ipa->event_lock);
5830 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005831 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005832
5833#ifdef WLAN_OPEN_SOURCE
5834 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5835 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5836 hdd_ipa->uc_op_work[i].msg = NULL;
5837 }
5838#endif
5839 }
5840
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305841 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005842 hdd_ctx->hdd_ipa = NULL;
5843
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305844 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005845}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005846
5847/**
5848 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5849 * @hdd_ctx: HDD global context
5850 *
5851 * Return: QDF_STATUS enumeration
5852 */
5853QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
5854{
5855 QDF_STATUS ret;
5856
5857 cds_ssr_protect(__func__);
5858 ret = __hdd_ipa_cleanup(hdd_ctx);
5859 cds_ssr_unprotect(__func__);
5860
5861 return ret;
5862}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005863#endif /* IPA_OFFLOAD */