blob: f03d3dbfc6a3ff5e60eda64c43b2333b3bfbfc6f [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
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080094typedef enum {
95 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
96 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
97 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
98 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
99 HDD_IPA_UC_OPCODE_STATS = 4,
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
103} hdd_ipa_uc_op_code;
104
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
Leo Chang07b28f62016-05-11 12:29:22 -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);
Mohit Khannafa99aea2016-05-12 21:43:13 -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) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001020 hdd_err("Dummy alloc fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001021 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1022 hdd_ipa_uc_stat_request(
Krunal Sonibe766b02016-03-10 13:00:44 -08001023 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001024 } else {
1025 kfree(dummy_ptr);
1026 }
1027
Anurag Chouhan210db072016-02-22 18:42:15 +05301028 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001029 HDD_IPA_UC_RT_DEBUG_PERIOD);
1030}
1031
1032/**
Yun Parkb187d542016-11-14 18:10:04 -08001033 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034 * @skb: packet pinter
1035 *
1036 * when free data packet, will be invoked by wlan client and will increase
1037 * free counter
1038 *
1039 * Return: none
1040 */
Jeff Johnsond7720632016-10-05 16:04:32 -07001041static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042{
1043 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301044 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001045 "%s: invalid hdd context", __func__);
1046 return;
1047 }
1048
1049 ghdd_ipa->ipa_rx_destructor_count++;
1050}
1051
1052/**
Yun Parkb187d542016-11-14 18:10:04 -08001053 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054 * @hdd_ctx: hdd main context
1055 *
1056 * free all rt debugging resources
1057 *
1058 * Return: none
1059 */
1060static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
1061{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001062 struct hdd_ipa_priv *hdd_ipa;
1063
1064 if (wlan_hdd_validate_context(hdd_ctx))
1065 return;
1066
1067 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001068
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301069 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001070
1071 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001072 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073 return;
1074 }
1075
Anurag Chouhan210db072016-02-22 18:42:15 +05301076 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001077 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1078 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1079 }
1080 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1081
1082 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301083 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1084 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001085 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301086 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001087}
1088
1089/**
Yun Parkb187d542016-11-14 18:10:04 -08001090 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001091 * @hdd_ctx: hdd main context
1092 *
1093 * alloc and initialize all rt debugging resources
1094 *
1095 * Return: none
1096 */
1097static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
1098{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001099 struct hdd_ipa_priv *hdd_ipa;
1100
1101 if (wlan_hdd_validate_context(hdd_ctx))
1102 return;
1103
1104 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301106 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301108 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109 sizeof(struct uc_rt_debug_info) *
1110 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1111 hdd_ipa->ipa_tx_forward = 0;
1112 hdd_ipa->ipa_rx_discard = 0;
1113 hdd_ipa->ipa_rx_net_send_count = 0;
1114 hdd_ipa->ipa_rx_internel_drop_count = 0;
1115 hdd_ipa->ipa_rx_destructor_count = 0;
1116
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 /* Reatime debug enable on feature enable */
1118 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001119 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001120 return;
1121 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001122
1123 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1124 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1125 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1126 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1127
Anurag Chouhan210db072016-02-22 18:42:15 +05301128 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001129 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301130 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001131 HDD_IPA_UC_RT_DEBUG_PERIOD);
1132
1133}
1134
1135/**
Yun Parkb187d542016-11-14 18:10:04 -08001136 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1137 * @hdd_ipa: HDD IPA struct
1138 *
1139 * Dump entries in struct hdd_ipa
1140 *
1141 * Return: none
1142 */
1143static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1144{
1145 int i;
1146
1147 /* HDD IPA */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001148 hdd_info("==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001149 "num_iface: %d\n"
1150 "rm_state: %d\n"
1151 "rm_lock: %p\n"
1152 "uc_rm_work: %p\n"
1153 "uc_op_work: %p\n"
1154 "wake_lock: %p\n"
1155 "wake_lock_work: %p\n"
1156 "wake_lock_released: %d\n"
1157 "prod_client: %d\n"
1158 "tx_ref_cnt: %d\n"
1159 "pm_queue_head----\n"
1160 "\thead: %p\n"
1161 "\ttail: %p\n"
1162 "\tqlen: %d\n"
1163 "pm_work: %p\n"
1164 "pm_lock: %p\n"
1165 "suspended: %d\n",
1166 hdd_ipa->num_iface,
1167 hdd_ipa->rm_state,
1168 &hdd_ipa->rm_lock,
1169 &hdd_ipa->uc_rm_work,
1170 &hdd_ipa->uc_op_work,
1171 &hdd_ipa->wake_lock,
1172 &hdd_ipa->wake_lock_work,
1173 hdd_ipa->wake_lock_released,
1174 hdd_ipa->prod_client,
1175 hdd_ipa->tx_ref_cnt.counter,
1176 hdd_ipa->pm_queue_head.head,
1177 hdd_ipa->pm_queue_head.tail,
1178 hdd_ipa->pm_queue_head.qlen,
1179 &hdd_ipa->pm_work,
1180 &hdd_ipa->pm_lock,
1181 hdd_ipa->suspended);
Srinivas Girigowda97852372017-03-06 16:52:59 -08001182 hdd_info("\npending_hw_desc_cnt: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001183 "hw_desc_cnt: %d\n"
1184 "q_lock: %p\n"
1185 "freeq_cnt: %d\n"
1186 "free_desc_head----\n"
1187 "\tnext: %p\n"
1188 "\tprev: %p\n"
1189 "pend_q_cnt: %d\n"
1190 "pend_desc_head----\n"
1191 "\tnext: %p\n"
1192 "\tprev: %p\n"
1193 "hdd_ctx: %p\n"
1194 "debugfs_dir: %p\n"
1195 "stats: %p\n"
1196 "ipv4_notifier: %p\n"
1197 "curr_prod_bw: %d\n"
1198 "curr_cons_bw: %d\n"
1199 "activated_fw_pipe: %d\n"
1200 "sap_num_connected_sta: %d\n"
1201 "sta_connected: %d\n",
1202 hdd_ipa->pending_hw_desc_cnt,
1203 hdd_ipa->hw_desc_cnt,
1204 &hdd_ipa->q_lock,
1205 hdd_ipa->freeq_cnt,
1206 hdd_ipa->free_desc_head.next,
1207 hdd_ipa->free_desc_head.prev,
1208 hdd_ipa->pend_q_cnt,
1209 hdd_ipa->pend_desc_head.next,
1210 hdd_ipa->pend_desc_head.prev,
1211 hdd_ipa->hdd_ctx,
1212 hdd_ipa->debugfs_dir,
1213 &hdd_ipa->stats,
1214 &hdd_ipa->ipv4_notifier,
1215 hdd_ipa->curr_prod_bw,
1216 hdd_ipa->curr_cons_bw,
1217 hdd_ipa->activated_fw_pipe,
1218 hdd_ipa->sap_num_connected_sta,
1219 (unsigned int)hdd_ipa->sta_connected
1220 );
Srinivas Girigowda97852372017-03-06 16:52:59 -08001221 hdd_info("\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001222 "rx_pipe_handle: 0x%x\n"
1223 "resource_loading: %d\n"
1224 "resource_unloading: %d\n"
1225 "pending_cons_req: %d\n"
1226 "pending_event----\n"
1227 "\tanchor.next: %p\n"
1228 "\tanchor.prev: %p\n"
1229 "\tcount: %d\n"
1230 "\tmax_size: %d\n"
1231 "event_lock: %p\n"
1232 "ipa_tx_packets_diff: %d\n"
1233 "ipa_rx_packets_diff: %d\n"
1234 "ipa_p_tx_packets: %d\n"
1235 "ipa_p_rx_packets: %d\n"
1236 "stat_req_reason: %d\n",
1237 hdd_ipa->tx_pipe_handle,
1238 hdd_ipa->rx_pipe_handle,
1239 hdd_ipa->resource_loading,
1240 hdd_ipa->resource_unloading,
1241 hdd_ipa->pending_cons_req,
1242 hdd_ipa->pending_event.anchor.next,
1243 hdd_ipa->pending_event.anchor.prev,
1244 hdd_ipa->pending_event.count,
1245 hdd_ipa->pending_event.max_size,
1246 &hdd_ipa->event_lock,
1247 hdd_ipa->ipa_tx_packets_diff,
1248 hdd_ipa->ipa_rx_packets_diff,
1249 hdd_ipa->ipa_p_tx_packets,
1250 hdd_ipa->ipa_p_rx_packets,
1251 hdd_ipa->stat_req_reason);
1252
Srinivas Girigowda97852372017-03-06 16:52:59 -08001253 hdd_info("assoc_stas_map([id]is_reserved/sta_id): ");
Yun Parkb187d542016-11-14 18:10:04 -08001254 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001255 hdd_info(" [%d]%d/%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001256 hdd_ipa->assoc_stas_map[i].is_reserved,
1257 hdd_ipa->assoc_stas_map[i].sta_id);
1258 }
1259}
1260
1261/**
1262 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1263 * @hdd_ipa: HDD IPA struct
1264 *
1265 * Dump entire struct hdd_ipa_sys_pipe
1266 *
1267 * Return: none
1268 */
1269static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1270{
1271 int i;
1272
1273 /* IPA SYS Pipes */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001274 hdd_info("==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001275
1276 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1277 struct hdd_ipa_sys_pipe *sys_pipe;
1278 struct ipa_sys_connect_params *ipa_sys_params;
1279
1280 sys_pipe = &hdd_ipa->sys_pipe[i];
1281 ipa_sys_params = &sys_pipe->ipa_sys_params;
1282
Srinivas Girigowda97852372017-03-06 16:52:59 -08001283 hdd_info("sys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001284 "\tconn_hdl: 0x%x\n"
1285 "\tconn_hdl_valid: %d\n"
1286 "\tnat_en: %d\n"
1287 "\thdr_len %d\n"
1288 "\thdr_additional_const_len: %d\n"
1289 "\thdr_ofst_pkt_size_valid: %d\n"
1290 "\thdr_ofst_pkt_size: %d\n"
1291 "\thdr_little_endian: %d\n"
1292 "\tmode: %d\n"
1293 "\tclient: %d\n"
1294 "\tdesc_fifo_sz: %d\n"
1295 "\tpriv: %p\n"
1296 "\tnotify: %p\n"
1297 "\tskip_ep_cfg: %d\n"
1298 "\tkeep_ipa_awake: %d\n",
1299 i,
1300 sys_pipe->conn_hdl,
1301 sys_pipe->conn_hdl_valid,
1302 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1303 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1304 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1305 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1306 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1307 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1308 ipa_sys_params->ipa_ep_cfg.mode.mode,
1309 ipa_sys_params->client,
1310 ipa_sys_params->desc_fifo_sz,
1311 ipa_sys_params->priv,
1312 ipa_sys_params->notify,
1313 ipa_sys_params->skip_ep_cfg,
1314 ipa_sys_params->keep_ipa_awake);
1315 }
1316}
1317
1318/**
1319 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1320 * @hdd_ipa: HDD IPA struct
1321 *
1322 * Dump entire struct hdd_ipa_iface_context
1323 *
1324 * Return: none
1325 */
1326static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1327{
1328 int i;
1329
1330 /* IPA Interface Contexts */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001331 hdd_info("==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001332
1333 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1334 struct hdd_ipa_iface_context *iface_context;
1335
1336 iface_context = &hdd_ipa->iface_context[i];
1337
Srinivas Girigowda97852372017-03-06 16:52:59 -08001338 hdd_info("iface_context[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001339 "\thdd_ipa: %p\n"
1340 "\tadapter: %p\n"
1341 "\ttl_context: %p\n"
1342 "\tcons_client: %d\n"
1343 "\tprod_client: %d\n"
1344 "\tiface_id: %d\n"
1345 "\tsta_id: %d\n"
1346 "\tinterface_lock: %p\n"
1347 "\tifa_address: 0x%x\n",
1348 i,
1349 iface_context->hdd_ipa,
1350 iface_context->adapter,
1351 iface_context->tl_context,
1352 iface_context->cons_client,
1353 iface_context->prod_client,
1354 iface_context->iface_id,
1355 iface_context->sta_id,
1356 &iface_context->interface_lock,
1357 iface_context->ifa_address);
1358 }
1359}
1360
1361/**
1362 * hdd_ipa_dump_info() - dump HDD IPA struct
1363 * @pHddCtx: hdd main context
1364 *
1365 * Dump entire struct hdd_ipa
1366 *
1367 * Return: none
1368 */
1369void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1370{
1371 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1372
1373 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1374 hdd_ipa_dump_sys_pipe(hdd_ipa);
1375 hdd_ipa_dump_iface_context(hdd_ipa);
1376}
1377
1378/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001379 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1380 * enabled
1381 *
1382 * This routine is called to set TX flow info if IPA is enabled
1383 *
1384 * Return: None
1385 */
1386void hdd_ipa_set_tx_flow_info(void)
1387{
1388 hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL;
1389 QDF_STATUS status;
1390 hdd_adapter_t *adapter;
1391 hdd_station_ctx_t *pHddStaCtx;
1392 hdd_ap_ctx_t *hdd_ap_ctx;
1393 hdd_hostapd_state_t *hostapd_state;
1394 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1395 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1396 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1397 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1398 const char *p2pMode = "DEV";
1399 hdd_context_t *hdd_ctx;
1400 cds_context_type *cds_ctx;
1401#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1402 uint8_t targetChannel = 0;
1403 uint8_t preAdapterChannel = 0;
1404 uint8_t channel24;
1405 uint8_t channel5;
1406 hdd_adapter_t *preAdapterContext = NULL;
1407 hdd_adapter_t *adapter2_4 = NULL;
1408 hdd_adapter_t *adapter5 = NULL;
1409 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1410#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1411 struct wlan_objmgr_psoc *psoc;
1412
1413 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1414 if (!hdd_ctx) {
1415 cds_err("HDD context is NULL");
1416 return;
1417 }
1418
1419 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1420 if (!cds_ctx) {
1421 cds_err("Invalid CDS Context");
1422 return;
1423 }
1424
1425 psoc = hdd_ctx->hdd_psoc;
1426 status = hdd_get_front_adapter(hdd_ctx, &adapterNode);
1427 while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) {
1428 adapter = adapterNode->pAdapter;
1429 switch (adapter->device_mode) {
1430 case QDF_STA_MODE:
1431 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1432 if (eConnectionState_Associated ==
1433 pHddStaCtx->conn_info.connState) {
1434 staChannel =
1435 pHddStaCtx->conn_info.operationChannel;
1436 qdf_copy_macaddr(&staBssid,
1437 &pHddStaCtx->conn_info.bssId);
1438#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1439 targetChannel = staChannel;
1440#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1441 }
1442 break;
1443 case QDF_P2P_CLIENT_MODE:
1444 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1445 if (eConnectionState_Associated ==
1446 pHddStaCtx->conn_info.connState) {
1447 p2pChannel =
1448 pHddStaCtx->conn_info.operationChannel;
1449 qdf_copy_macaddr(&p2pBssid,
1450 &pHddStaCtx->conn_info.bssId);
1451 p2pMode = "CLI";
1452#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1453 targetChannel = p2pChannel;
1454#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1455 }
1456 break;
1457 case QDF_P2P_GO_MODE:
1458 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1459 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1460 if (hostapd_state->bssState == BSS_START
1461 && hostapd_state->qdf_status ==
1462 QDF_STATUS_SUCCESS) {
1463 p2pChannel = hdd_ap_ctx->operatingChannel;
1464 qdf_copy_macaddr(&p2pBssid,
1465 &adapter->macAddressCurrent);
1466#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1467 targetChannel = p2pChannel;
1468#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1469 }
1470 p2pMode = "GO";
1471 break;
1472 case QDF_SAP_MODE:
1473 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1474 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1475 if (hostapd_state->bssState == BSS_START
1476 && hostapd_state->qdf_status ==
1477 QDF_STATUS_SUCCESS) {
1478 apChannel = hdd_ap_ctx->operatingChannel;
1479 qdf_copy_macaddr(&apBssid,
1480 &adapter->macAddressCurrent);
1481#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1482 targetChannel = apChannel;
1483#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1484 }
1485 break;
1486 case QDF_IBSS_MODE:
1487 default:
1488 break;
1489 }
1490#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1491 if (targetChannel) {
1492 /*
1493 * This is first adapter detected as active
1494 * set as default for none concurrency case
1495 */
1496 if (!preAdapterChannel) {
1497 /* If IPA UC data path is enabled,
1498 * target should reserve extra tx descriptors
1499 * for IPA data path.
1500 * Then host data path should allow less TX
1501 * packet pumping in case IPA
1502 * data path enabled
1503 */
1504 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1505 (QDF_SAP_MODE == adapter->device_mode)) {
1506 adapter->tx_flow_low_watermark =
1507 hdd_ctx->config->TxFlowLowWaterMark +
1508 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1509 } else {
1510 adapter->tx_flow_low_watermark =
1511 hdd_ctx->config->
1512 TxFlowLowWaterMark;
1513 }
1514 adapter->tx_flow_high_watermark_offset =
1515 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1516 cdp_fc_ll_set_tx_pause_q_depth(soc,
1517 adapter->sessionId,
1518 hdd_ctx->config->TxFlowMaxQueueDepth);
1519 cds_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
1520 adapter->device_mode,
1521 targetChannel,
1522 adapter->tx_flow_low_watermark,
1523 adapter->tx_flow_low_watermark +
1524 adapter->tx_flow_high_watermark_offset,
1525 hdd_ctx->config->TxFlowMaxQueueDepth);
1526 preAdapterChannel = targetChannel;
1527 preAdapterContext = adapter;
1528 } else {
1529 /*
1530 * SCC, disable TX flow control for both
1531 * SCC each adapter cannot reserve dedicated
1532 * channel resource, as a result, if any adapter
1533 * blocked OS Q by flow control,
1534 * blocked adapter will lost chance to recover
1535 */
1536 if (preAdapterChannel == targetChannel) {
1537 /* Current adapter */
1538 adapter->tx_flow_low_watermark = 0;
1539 adapter->
1540 tx_flow_high_watermark_offset = 0;
1541 cdp_fc_ll_set_tx_pause_q_depth(soc,
1542 adapter->sessionId,
1543 hdd_ctx->config->
1544 TxHbwFlowMaxQueueDepth);
1545 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1546 hdd_device_mode_to_string(
1547 adapter->device_mode),
1548 adapter->device_mode,
1549 targetChannel,
1550 adapter->tx_flow_low_watermark,
1551 adapter->tx_flow_low_watermark +
1552 adapter->
1553 tx_flow_high_watermark_offset,
1554 hdd_ctx->config->
1555 TxHbwFlowMaxQueueDepth);
1556
1557 if (!preAdapterContext) {
1558 cds_err("SCC: Previous adapter context NULL");
1559 continue;
1560 }
1561
1562 /* Previous adapter */
1563 preAdapterContext->
1564 tx_flow_low_watermark = 0;
1565 preAdapterContext->
1566 tx_flow_high_watermark_offset = 0;
1567 cdp_fc_ll_set_tx_pause_q_depth(soc,
1568 preAdapterContext->sessionId,
1569 hdd_ctx->config->
1570 TxHbwFlowMaxQueueDepth);
1571 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1572 hdd_device_mode_to_string(
1573 preAdapterContext->device_mode
1574 ),
1575 preAdapterContext->device_mode,
1576 targetChannel,
1577 preAdapterContext->
1578 tx_flow_low_watermark,
1579 preAdapterContext->
1580 tx_flow_low_watermark +
1581 preAdapterContext->
1582 tx_flow_high_watermark_offset,
1583 hdd_ctx->config->
1584 TxHbwFlowMaxQueueDepth);
1585 }
1586 /*
1587 * MCC, each adapter will have dedicated
1588 * resource
1589 */
1590 else {
1591 /* current channel is 2.4 */
1592 if (targetChannel <=
1593 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1594 channel24 = targetChannel;
1595 channel5 = preAdapterChannel;
1596 adapter2_4 = adapter;
1597 adapter5 = preAdapterContext;
1598 } else {
1599 /* Current channel is 5 */
1600 channel24 = preAdapterChannel;
1601 channel5 = targetChannel;
1602 adapter2_4 = preAdapterContext;
1603 adapter5 = adapter;
1604 }
1605
1606 if (!adapter5) {
1607 cds_err("MCC: 5GHz adapter context NULL");
1608 continue;
1609 }
1610 adapter5->tx_flow_low_watermark =
1611 hdd_ctx->config->
1612 TxHbwFlowLowWaterMark;
1613 adapter5->
1614 tx_flow_high_watermark_offset =
1615 hdd_ctx->config->
1616 TxHbwFlowHighWaterMarkOffset;
1617 cdp_fc_ll_set_tx_pause_q_depth(soc,
1618 adapter5->sessionId,
1619 hdd_ctx->config->
1620 TxHbwFlowMaxQueueDepth);
1621 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1622 hdd_device_mode_to_string(
1623 adapter5->device_mode),
1624 adapter5->device_mode,
1625 channel5,
1626 adapter5->tx_flow_low_watermark,
1627 adapter5->
1628 tx_flow_low_watermark +
1629 adapter5->
1630 tx_flow_high_watermark_offset,
1631 hdd_ctx->config->
1632 TxHbwFlowMaxQueueDepth);
1633
1634 if (!adapter2_4) {
1635 cds_err("MCC: 2.4GHz adapter context NULL");
1636 continue;
1637 }
1638 adapter2_4->tx_flow_low_watermark =
1639 hdd_ctx->config->
1640 TxLbwFlowLowWaterMark;
1641 adapter2_4->
1642 tx_flow_high_watermark_offset =
1643 hdd_ctx->config->
1644 TxLbwFlowHighWaterMarkOffset;
1645 cdp_fc_ll_set_tx_pause_q_depth(soc,
1646 adapter2_4->sessionId,
1647 hdd_ctx->config->
1648 TxLbwFlowMaxQueueDepth);
1649 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1650 hdd_device_mode_to_string(
1651 adapter2_4->device_mode),
1652 adapter2_4->device_mode,
1653 channel24,
1654 adapter2_4->
1655 tx_flow_low_watermark,
1656 adapter2_4->
1657 tx_flow_low_watermark +
1658 adapter2_4->
1659 tx_flow_high_watermark_offset,
1660 hdd_ctx->config->
1661 TxLbwFlowMaxQueueDepth);
1662
1663 }
1664 }
1665 }
1666 targetChannel = 0;
1667#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1668 status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext);
1669 adapterNode = pNext;
1670 }
1671 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1672}
1673
1674/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001675 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001677 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1678 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001679 *
1680 * Return: true if IPA is enabled, false otherwise
1681 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001682static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001683 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1684{
1685 struct hdd_ipa_priv *hdd_ipa;
1686
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001687 *ipa_tx_diff = 0;
1688 *ipa_rx_diff = 0;
1689
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001690 if (wlan_hdd_validate_context(hdd_ctx))
1691 return;
1692
1693 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1694
1695 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1696 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 return;
1698 }
1699
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301700 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1702 (false == hdd_ipa->resource_loading)) {
1703 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1704 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001705 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001706 *ipa_tx_diff, *ipa_rx_diff);
1707 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301708 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709 return;
1710}
1711
1712/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001713 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1714 * @hdd_ctx: Global HDD context
1715 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1716 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1717 *
1718 * Return: true if IPA is enabled, false otherwise
1719 */
1720void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1721 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1722{
1723 cds_ssr_protect(__func__);
1724 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1725 cds_ssr_unprotect(__func__);
1726}
1727
1728/**
1729 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730 * @adapter: network adapter
1731 * @reason: STAT REQ Reason
1732 *
1733 * Return: None
1734 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001735static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001737 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738 struct hdd_ipa_priv *hdd_ipa;
1739
1740 if (!adapter) {
1741 return;
1742 }
1743
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001744 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1745
1746 if (wlan_hdd_validate_context(hdd_ctx))
1747 return;
1748
1749 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1750 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1751 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752 return;
1753 }
1754
Yun Parkb187d542016-11-14 18:10:04 -08001755 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301756 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1758 (false == hdd_ipa->resource_loading)) {
1759 hdd_ipa->stat_req_reason = reason;
1760 wma_cli_set_command(
1761 (int)adapter->sessionId,
1762 (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
1763 0, VDEV_CMD);
1764 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301765 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766}
1767
1768/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001769 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1770 * @adapter: network adapter
1771 * @reason: STAT REQ Reason
1772 *
1773 * Return: None
1774 */
1775void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1776{
1777 cds_ssr_protect(__func__);
1778 __hdd_ipa_uc_stat_request(adapter, reason);
1779 cds_ssr_unprotect(__func__);
1780}
1781
1782/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1784 * @hdd_ipa: Global HDD IPA context
1785 * @sta_add: Should station be added
1786 * @sta_id: ID of the station being queried
1787 *
1788 * Return: true if the station was found
1789 */
1790static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1791 bool sta_add, uint8_t sta_id)
1792{
1793 bool sta_found = false;
1794 uint8_t idx;
1795 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1796 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1797 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1798 sta_found = true;
1799 break;
1800 }
1801 }
1802 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301803 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001804 "%s: STA ID %d already exist, cannot add",
1805 __func__, sta_id);
1806 return sta_found;
1807 }
1808 if (sta_add) {
1809 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1810 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1811 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1812 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1813 return sta_found;
1814 }
1815 }
1816 }
1817 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301818 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001819 "%s: STA ID %d does not exist, cannot delete",
1820 __func__, sta_id);
1821 return sta_found;
1822 }
1823 if (!sta_add) {
1824 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1825 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1826 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1827 hdd_ipa->assoc_stas_map[idx].is_reserved =
1828 false;
1829 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1830 return sta_found;
1831 }
1832 }
1833 }
1834 return sta_found;
1835}
1836
1837/**
1838 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1839 * @hdd_ipa: Global HDD IPA context
1840 *
1841 * Return: 0 on success, negative errno if error
1842 */
1843static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1844{
1845 int result;
1846 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001847 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848
1849 /* ACTIVATE TX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001850 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001851 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1852 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001853 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1854 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301855 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001856 "%s: Enable TX PIPE fail, code %d",
1857 __func__, result);
1858 return result;
1859 }
1860 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1861 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301862 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001863 "%s: Resume TX PIPE fail, code %d",
1864 __func__, result);
1865 return result;
1866 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001867 cdp_ipa_set_active(soc,
1868 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1869 true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870
1871 /* ACTIVATE RX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001872 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001873 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1874 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001875 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1876 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301877 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878 "%s: Enable RX PIPE fail, code %d",
1879 __func__, result);
1880 return result;
1881 }
1882 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1883 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301884 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885 "%s: Resume RX PIPE fail, code %d",
1886 __func__, result);
1887 return result;
1888 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001889 cdp_ipa_set_active(soc,
1890 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1891 true, false);
Leo Change3e49442015-10-26 20:07:13 -07001892 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001893 return 0;
1894}
1895
1896/**
1897 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1898 * @hdd_ipa: Global HDD IPA context
1899 *
1900 * Return: 0 on success, negative errno if error
1901 */
1902static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1903{
1904 int result;
1905
Leo Change3e49442015-10-26 20:07:13 -07001906 hdd_ipa->ipa_pipes_down = true;
1907
Srinivas Girigowda97852372017-03-06 16:52:59 -08001908 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001909 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
1910 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301911 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001912 "%s: Suspend RX PIPE fail, code %d",
1913 __func__, result);
1914 return result;
1915 }
1916 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1917 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301918 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001919 "%s: Disable RX PIPE fail, code %d",
1920 __func__, result);
1921 return result;
1922 }
1923
Srinivas Girigowda97852372017-03-06 16:52:59 -08001924 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001925 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
1926 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301927 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001928 "%s: Suspend TX PIPE fail, code %d",
1929 __func__, result);
1930 return result;
1931 }
1932 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1933 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301934 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001935 "%s: Disable TX PIPE fail, code %d",
1936 __func__, result);
1937 return result;
1938 }
1939
1940 return 0;
1941}
1942
1943/**
1944 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1945 * @hdd_ipa: Global HDD IPA context
1946 *
1947 * Return: 0 on success, negative errno if error
1948 */
1949static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1950{
1951 hdd_ipa->activated_fw_pipe = 0;
1952 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001953
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 /* If RM feature enabled
1955 * Request PROD Resource first
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08001956 * PROD resource may return sync or async manners
1957 */
Yun Park4cab6ee2015-10-27 11:43:40 -07001958 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
1959 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1960 /* RM PROD request sync return
1961 * enable pipe immediately
1962 */
1963 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301964 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001965 "%s: IPA WDI Pipe activation failed",
1966 __func__);
1967 hdd_ipa->resource_loading = false;
1968 return -EBUSY;
1969 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 }
1971 } else {
1972 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001973 * Just enabled all the PIPEs
1974 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001975 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301976 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001977 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001978 __func__);
1979 hdd_ipa->resource_loading = false;
1980 return -EBUSY;
1981 }
1982 hdd_ipa->resource_loading = false;
1983 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001984
Srinivas Girigowda97852372017-03-06 16:52:59 -08001985 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001986 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001987 return 0;
1988}
1989
1990/**
1991 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1992 * @hdd_ipa: Global HDD IPA context
1993 *
1994 * Return: None
1995 */
1996static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1997{
1998 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001999 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002000
Yun Park7c4f31b2016-11-30 10:09:21 -08002001 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
2002 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2003 QDF_ASSERT(0);
2004 return;
2005 }
2006
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002007 hdd_ipa->resource_unloading = true;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002008 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW RX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002009 cdp_ipa_set_active(soc,
2010 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2011 false, false);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002012 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW TX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002013 cdp_ipa_set_active(soc,
2014 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2015 false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002016}
2017
2018/**
2019 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2020 * @context: User context registered with TL (the IPA Global context is
2021 * registered
2022 * @rxpkt: Packet containing the notification
2023 * @staid: ID of the station associated with the packet
2024 *
2025 * Return: None
2026 */
2027static void
2028hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
2029{
2030 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302031 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002032
2033 /*
2034 * When SSR is going on or driver is unloading, just return.
2035 */
2036 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302037 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002039
2040 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2041 return;
2042
Srinivas Girigowda97852372017-03-06 16:52:59 -08002043 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002044 __func__, event);
2045
2046 switch (event) {
2047 case IPA_RM_RESOURCE_GRANTED:
2048 /* Differed RM Granted */
2049 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302050 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051 if ((false == hdd_ipa->resource_unloading) &&
2052 (!hdd_ipa->activated_fw_pipe)) {
2053 hdd_ipa_uc_enable_pipes(hdd_ipa);
2054 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302055 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002056 break;
2057
2058 case IPA_RM_RESOURCE_RELEASED:
2059 /* Differed RM Released */
2060 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002061 break;
2062
2063 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302064 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002065 "%s, invalid event code %d", __func__, event);
2066 break;
2067 }
2068}
2069
2070/**
2071 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2072 * @hdd_ipa: Global HDD IPA context
2073 * @event: IPA resource manager event to be deferred
2074 *
2075 * This function is called when a resource manager event is received
2076 * from firmware in interrupt context. This function will defer the
2077 * handling to the OL RX thread
2078 *
2079 * Return: None
2080 */
2081static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2082{
2083 enum ipa_rm_event event;
2084 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2085 struct uc_rm_work_struct, work);
2086 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2087 struct hdd_ipa_priv, uc_rm_work);
2088
2089 cds_ssr_protect(__func__);
2090 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002091 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002092 "%s, posted event %d", __func__, event);
2093
2094 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2095 cds_ssr_unprotect(__func__);
2096
2097 return;
2098}
2099
2100/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002101 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2102 * @ipa_ctxt: hdd ipa local context
2103 *
2104 * Will handle IPA UC image loaded indication comes from IPA kernel
2105 *
2106 * Return: None
2107 */
2108static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt)
2109{
2110 struct ipa_wdi_out_params pipe_out;
2111
2112 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
2113 if (true == ipa_ctxt->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002114 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002115 __func__);
2116 return;
2117 }
2118
2119 ipa_ctxt->uc_loaded = true;
2120 /* Connect pipe */
2121 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2122 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2123 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
2124 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2125 "%s : TX PIPE Handle %d, DBPA 0x%llx",
2126 __func__, ipa_ctxt->tx_pipe_handle,
2127 (unsigned long long) pipe_out.uc_door_bell_pa);
2128
2129 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2130 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
2131 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2132 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2133 "%s : RX PIPE Handle %d, DBPA 0x%llx",
2134 __func__, ipa_ctxt->rx_pipe_handle,
2135 (unsigned long long) pipe_out.uc_door_bell_pa);
2136
2137 /* If already any STA connected, enable IPA/FW PIPEs */
2138 if (ipa_ctxt->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002139 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002140 "Client already connected, enable IPA/FW PIPEs");
2141 hdd_ipa_uc_handle_first_con(ipa_ctxt);
2142 }
2143}
2144
2145/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002146 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2147 * @op_msg: operation message received from firmware
2148 * @usr_ctxt: user context registered with TL (we register the HDD Global
2149 * context)
2150 *
2151 * Return: None
2152 */
2153static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2154{
2155 struct op_msg_type *msg = op_msg;
2156 struct ipa_uc_fw_stats *uc_fw_stat;
2157 struct IpaHwStatsWDIInfoData_t ipa_stat;
2158 struct hdd_ipa_priv *hdd_ipa;
2159 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302160 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161
2162 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302163 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002164 return;
2165 }
2166
2167 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302168 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002169 "%s, INVALID OPCODE %d", __func__, msg->op_code);
2170 return;
2171 }
2172
2173 hdd_ctx = (hdd_context_t *) usr_ctxt;
2174
2175 /*
2176 * When SSR is going on or driver is unloading, just return.
2177 */
2178 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302179 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302180 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002181 return;
2182 }
2183
2184 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2185
Govind Singhb6a89772016-08-12 11:23:35 +05302186 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002187 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002188
2189 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2190 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302191 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002192 hdd_ipa->activated_fw_pipe++;
2193 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2194 hdd_ipa->resource_loading = false;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002195 if (hdd_ipa->wdi_enabled == false) {
2196 hdd_ipa->wdi_enabled = true;
2197 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2198 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2199 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002200 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002201 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002202 if (hdd_ipa->pending_cons_req)
2203 ipa_rm_notify_completion(
2204 IPA_RM_RESOURCE_GRANTED,
2205 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002206 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002207 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302208 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002209 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002210 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302211 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002212 hdd_ipa->activated_fw_pipe--;
2213 if (!hdd_ipa->activated_fw_pipe) {
2214 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002215 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2216 ipa_rm_release_resource(
2217 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002218 /*
2219 * Sync return success from IPA
2220 * Enable/resume all the PIPEs
2221 */
Yun Park5b635012015-12-02 15:05:01 -08002222 hdd_ipa->resource_unloading = false;
2223 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2224 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002225 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302226 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002227 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002228 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002229 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002230 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302231 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002232 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002233 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002234 "CE RING SIZE: %d\n"
2235 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002236 (unsigned long long)res->ce_sr_base_paddr,
2237 res->ce_sr_ring_size,
2238 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302239 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002240 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002241 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002242 "COMP RING SIZE: %d\n"
2243 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002244 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002245 (unsigned long long)res->tx_comp_ring_base_paddr,
2246 res->tx_comp_ring_size,
2247 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08002248 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302249 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002250 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002251 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002252 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002253 "IND RING DBELL : 0x%llx\n"
2254 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002255 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08002256 "NUM TX FWD OK : %llu\n"
2257 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08002258 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002259 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08002260 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
2261 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002262 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08002263 hdd_ipa->stats.num_tx_fwd_ok,
2264 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302265 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002266 "==== IPA_UC WLAN_HOST CONTROL ====\n"
2267 "SAP NUM STAs: %d\n"
2268 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08002269 "CONCURRENT MODE: %s\n"
2270 "TX PIPE HDL: 0x%x\n"
2271 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002272 "RSC LOADING : %d\n"
2273 "RSC UNLOADING : %d\n"
2274 "PNDNG CNS RQT : %d",
2275 hdd_ipa->sap_num_connected_sta,
2276 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08002277 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002278 hdd_ipa->tx_pipe_handle,
2279 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08002280 hdd_ipa->resource_loading,
2281 hdd_ipa->resource_unloading,
2282 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002283
2284 /* STATs from FW */
2285 uc_fw_stat = (struct ipa_uc_fw_stats *)
2286 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302287 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002288 "==== IPA_UC WLAN_FW TX ====\n"
2289 "COMP RING BASE: 0x%x\n"
2290 "COMP RING SIZE: %d\n"
2291 "COMP RING DBELL : 0x%x\n"
2292 "COMP RING DBELL IND VAL : %d\n"
2293 "COMP RING DBELL CACHED VAL : %d\n"
2294 "COMP RING DBELL CACHED VAL : %d\n"
2295 "PKTS ENQ : %d\n"
2296 "PKTS COMP : %d\n"
2297 "IS SUSPEND : %d\n"
2298 "RSVD : 0x%x",
2299 uc_fw_stat->tx_comp_ring_base,
2300 uc_fw_stat->tx_comp_ring_size,
2301 uc_fw_stat->tx_comp_ring_dbell_addr,
2302 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2303 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2304 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2305 uc_fw_stat->tx_pkts_enqueued,
2306 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002307 uc_fw_stat->tx_is_suspend,
2308 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302309 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002310 "==== IPA_UC WLAN_FW RX ====\n"
2311 "IND RING BASE: 0x%x\n"
2312 "IND RING SIZE: %d\n"
2313 "IND RING DBELL : 0x%x\n"
2314 "IND RING DBELL IND VAL : %d\n"
2315 "IND RING DBELL CACHED VAL : %d\n"
2316 "RDY IND ADDR : 0x%x\n"
2317 "RDY IND CACHE VAL : %d\n"
2318 "RFIL IND : %d\n"
2319 "NUM PKT INDICAT : %d\n"
2320 "BUF REFIL : %d\n"
2321 "NUM DROP NO SPC : %d\n"
2322 "NUM DROP NO BUF : %d\n"
2323 "IS SUSPND : %d\n"
2324 "RSVD : 0x%x\n",
2325 uc_fw_stat->rx_ind_ring_base,
2326 uc_fw_stat->rx_ind_ring_size,
2327 uc_fw_stat->rx_ind_ring_dbell_addr,
2328 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2329 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2330 uc_fw_stat->rx_ind_ring_rdidx_addr,
2331 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2332 uc_fw_stat->rx_refill_idx,
2333 uc_fw_stat->rx_num_pkts_indicated,
2334 uc_fw_stat->rx_buf_refilled,
2335 uc_fw_stat->rx_num_ind_drop_no_space,
2336 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002337 uc_fw_stat->rx_is_suspend,
2338 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339 /* STATs from IPA */
2340 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302341 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002342 "==== IPA_UC IPA TX ====\n"
2343 "NUM PROCD : %d\n"
2344 "CE DBELL : 0x%x\n"
2345 "NUM DBELL FIRED : %d\n"
2346 "COMP RNG FULL : %d\n"
2347 "COMP RNG EMPT : %d\n"
2348 "COMP RNG USE HGH : %d\n"
2349 "COMP RNG USE LOW : %d\n"
2350 "BAM FIFO FULL : %d\n"
2351 "BAM FIFO EMPT : %d\n"
2352 "BAM FIFO USE HGH : %d\n"
2353 "BAM FIFO USE LOW : %d\n"
2354 "NUM DBELL : %d\n"
2355 "NUM UNEXP DBELL : %d\n"
2356 "NUM BAM INT HDL : 0x%x\n"
2357 "NUM BAM INT NON-RUN : 0x%x\n"
2358 "NUM QMB INT HDL : 0x%x",
2359 ipa_stat.tx_ch_stats.num_pkts_processed,
2360 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2361 ipa_stat.tx_ch_stats.num_db_fired,
2362 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2363 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2364 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2365 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2366 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2367 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2368 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2369 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2370 ipa_stat.tx_ch_stats.num_db,
2371 ipa_stat.tx_ch_stats.num_unexpected_db,
2372 ipa_stat.tx_ch_stats.num_bam_int_handled,
2373 ipa_stat.tx_ch_stats.
2374 num_bam_int_in_non_runnning_state,
2375 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2376
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302377 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002378 "==== IPA_UC IPA RX ====\n"
2379 "MAX OST PKT : %d\n"
2380 "NUM PKT PRCSD : %d\n"
2381 "RNG RP : 0x%x\n"
2382 "COMP RNG FULL : %d\n"
2383 "COMP RNG EMPT : %d\n"
2384 "COMP RNG USE HGH : %d\n"
2385 "COMP RNG USE LOW : %d\n"
2386 "BAM FIFO FULL : %d\n"
2387 "BAM FIFO EMPT : %d\n"
2388 "BAM FIFO USE HGH : %d\n"
2389 "BAM FIFO USE LOW : %d\n"
2390 "NUM DB : %d\n"
2391 "NUM UNEXP DB : %d\n"
2392 "NUM BAM INT HNDL : 0x%x\n",
2393 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2394 ipa_stat.rx_ch_stats.num_pkts_processed,
2395 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2396 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2397 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2398 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2399 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2400 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2401 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2402 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2403 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2404 ipa_stat.rx_ch_stats.num_db,
2405 ipa_stat.rx_ch_stats.num_unexpected_db,
2406 ipa_stat.rx_ch_stats.num_bam_int_handled);
2407 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2408 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2409 /* STATs from FW */
2410 uc_fw_stat = (struct ipa_uc_fw_stats *)
2411 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302412 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002413 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2414 uc_fw_stat->tx_pkts_completed,
2415 hdd_ipa->ipa_p_tx_packets);
2416 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2417 (uc_fw_stat->rx_num_ind_drop_no_space +
2418 uc_fw_stat->rx_num_ind_drop_no_buf +
2419 uc_fw_stat->rx_num_pkts_indicated),
2420 hdd_ipa->ipa_p_rx_packets);
2421
2422 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2423 hdd_ipa->ipa_p_rx_packets =
2424 (uc_fw_stat->rx_num_ind_drop_no_space +
2425 uc_fw_stat->rx_num_ind_drop_no_buf +
2426 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302427 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002428 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2429 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2430 hdd_ipa_uc_loaded_handler(hdd_ipa);
2431 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 } else {
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002433 HDD_IPA_LOG(LOGE, "INVALID REASON %d",
2434 hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002435 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302436 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002437}
2438
2439
2440/**
2441 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2442 * @adapter: device adapter instance
2443 * @offload_type: MCC or SCC
2444 * @enable: TX offload enable or disable
2445 *
2446 * Return: none
2447 */
2448static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002449 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002450{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002451 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002452 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002453 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002454 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002455
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002456 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002457 return;
2458
Yun Park8292dcb2016-10-07 16:46:06 -07002459 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002460 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002461
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002462 if (!iface_context) {
2463 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2464 "Interface context is NULL");
2465 return;
2466 }
2467
2468 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002469 /* IPA offload status is already set as desired */
2470 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002471 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
2472 "IPA offload status is already set",
2473 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002474 return;
2475 }
2476
Yun Park4540e862016-11-10 16:30:06 -08002477 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2478 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2479 "invalid session id: %d, offload_type=%d, enable=%d",
2480 adapter->sessionId, offload_type, enable);
2481 return;
2482 }
2483
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302484 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002485 sizeof(ipa_offload_enable_disable));
2486 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002487 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002488 ipa_offload_enable_disable.enable = enable;
2489
Srinivas Girigowda97852372017-03-06 16:52:59 -08002490 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park8292dcb2016-10-07 16:46:06 -07002491 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002492 ipa_offload_enable_disable.offload_type,
2493 ipa_offload_enable_disable.vdev_id,
2494 ipa_offload_enable_disable.enable);
2495
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302496 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002497 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2498 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302499 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002500 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2501 __func__,
2502 ipa_offload_enable_disable.offload_type,
2503 ipa_offload_enable_disable.vdev_id,
2504 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002505 } else {
2506 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002507 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002508 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002509 }
2510}
2511
2512/**
2513 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2514 * @work: uC OP work
2515 *
2516 * Return: None
2517 */
2518static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2519{
2520 struct op_msg_type *msg;
2521 struct uc_op_work_struct *uc_op_work = container_of(work,
2522 struct uc_op_work_struct, work);
2523 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2524
2525 cds_ssr_protect(__func__);
2526
2527 msg = uc_op_work->msg;
2528 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002529 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002530 "%s, posted msg %d", __func__, msg->op_code);
2531
2532 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2533
2534 cds_ssr_unprotect(__func__);
2535
2536 return;
2537}
2538
2539/**
2540 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2541 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2542 * @op_msg: operation message received from firmware
2543 * @hdd_ctx: Global HDD context
2544 *
2545 * Return: None
2546 */
2547static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2548{
2549 struct hdd_ipa_priv *hdd_ipa;
2550 struct op_msg_type *msg;
2551 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302552 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002553
2554 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302555 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002556 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002557
2558 msg = (struct op_msg_type *)op_msg;
2559 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2560
2561 if (unlikely(!hdd_ipa))
2562 goto end;
2563
2564 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302565 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002566 __func__, msg->op_code);
2567 goto end;
2568 }
2569
2570 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2571 if (uc_op_work->msg)
2572 /* When the same uC OPCODE is already pended, just return */
2573 goto end;
2574
2575 uc_op_work->msg = msg;
2576 schedule_work(&uc_op_work->work);
2577 return;
2578
2579end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302580 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002581}
2582
2583/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002584 * hdd_ipa_init_uc_op_work - init ipa uc op work
2585 * @work: struct work_struct
2586 * @work_handler: work_handler
2587 *
2588 * Return: none
2589 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002590static void hdd_ipa_init_uc_op_work(struct work_struct *work,
2591 work_func_t work_handler)
2592{
2593 INIT_WORK(work, work_handler);
2594}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002595
Rajeev Kumar217f2172016-01-06 18:11:55 -08002596/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002597 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2598 * @hdd_ctx: Global HDD context
2599 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302600 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002601 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002602QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002603{
2604 struct ipa_wdi_in_params pipe_in;
2605 struct ipa_wdi_out_params pipe_out;
2606 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002607 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07002608 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002609 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2610 int ret;
2611 QDF_STATUS stat = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002613 ENTER();
2614
Yun Parkbaa62862017-01-18 13:43:34 -08002615 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002616 if (!pdev || !soc) {
2617 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkbaa62862017-01-18 13:43:34 -08002618 stat = QDF_STATUS_E_FAILURE;
2619 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002620 }
Yun Parkbaa62862017-01-18 13:43:34 -08002621
2622 cdp_ipa_get_resource(soc, (void *)pdev, &ipa_ctxt->ipa_resource);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002623 if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) ||
2624 (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2625 (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2626 (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2627 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2628 "IPA UC resource alloc fail");
2629 return QDF_STATUS_E_FAILURE;
2630 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002631 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2632 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302633 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2634 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002635
Anurag Chouhanffb21542016-02-17 14:33:03 +05302636 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302637
2638 if (!cds_is_driver_recovering()) {
2639 qdf_mutex_create(&ipa_ctxt->event_lock);
2640 qdf_mutex_create(&ipa_ctxt->ipa_lock);
2641 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002642
2643 /* TX PIPE */
2644 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2645 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2646 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2647 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2648 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2649 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2650 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2651 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2652 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2653 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2654 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2655 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2656 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002657 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2658 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002659 pipe_in.sys.keep_ipa_awake = true;
2660 }
2661
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002662 pipe_in.u.dl.comp_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002663 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002664 pipe_in.u.dl.comp_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002665 ipa_ctxt->ipa_resource.tx_comp_ring_size *
2666 sizeof(qdf_dma_addr_t);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002667 pipe_in.u.dl.ce_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002668 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002669 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
2670 pipe_in.u.dl.ce_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002671 ipa_ctxt->ipa_resource.ce_sr_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002672 pipe_in.u.dl.num_tx_buffers =
Yun Parkbaa62862017-01-18 13:43:34 -08002673 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002674
Yun Parkbaa62862017-01-18 13:43:34 -08002675 qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in,
2676 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002677 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08002678 IPA_CLIENT_WLAN1_CONS);
2679
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002680 if (true == ipa_ctxt->uc_loaded) {
2681 /* Connect WDI IPA PIPE */
Yun Parkbaa62862017-01-18 13:43:34 -08002682 ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2683 if (ret) {
2684 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2685 "ipa_connect_wdi_pipe falied for Tx: ret=%d",
2686 ret);
2687 stat = QDF_STATUS_E_FAILURE;
2688 goto fail_return;
2689 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002690 /* Micro Controller Doorbell register */
Srinivas Girigowda97852372017-03-06 16:52:59 -08002691 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08002692 "CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
2693 (unsigned int)pipe_out.uc_door_bell_pa,
2694 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002695
2696 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Yun Parkbaa62862017-01-18 13:43:34 -08002697
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002698 /* WLAN TX PIPE Handle */
2699 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002700 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08002701 "TX : 0x%x, %d, 0x%x, 0x%x, %d, %d, 0x%x",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002702 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
2703 pipe_in.u.dl.comp_ring_size,
2704 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
2705 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
2706 pipe_in.u.dl.ce_ring_size,
2707 pipe_in.u.dl.num_tx_buffers,
2708 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
2709 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002710
2711 /* RX PIPE */
2712 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2713 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
2714 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
2715 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
2716 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2717 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
2718 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
2719 sizeof(struct sps_iovec);
2720 pipe_in.sys.notify = hdd_ipa_w2i_cb;
2721 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302722 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkbaa62862017-01-18 13:43:34 -08002723 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002724 pipe_in.sys.keep_ipa_awake = true;
2725 }
2726
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002727 pipe_in.u.ul.rdy_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002728 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002729 pipe_in.u.ul.rdy_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002730 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002731 pipe_in.u.ul.rdy_ring_rp_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002732 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002733 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Yun Parkbaa62862017-01-18 13:43:34 -08002734
2735 qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in,
2736 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002737 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08002738 IPA_CLIENT_WLAN1_PROD);
2739
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002740 if (true == ipa_ctxt->uc_loaded) {
Yun Parkbaa62862017-01-18 13:43:34 -08002741 ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2742 if (ret) {
2743 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2744 "ipa_connect_wdi_pipe falied for Rx: ret=%d",
2745 ret);
2746 stat = QDF_STATUS_E_FAILURE;
2747 goto fail_return;
2748
2749 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002750 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2751 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002752 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08002753 "PROD DB pipe out 0x%x TX PIPE Handle 0x%x",
2754 (unsigned int)pipe_out.uc_door_bell_pa,
2755 ipa_ctxt->tx_pipe_handle);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002756 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002757 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
2758 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
2759 pipe_in.u.ul.rdy_ring_size,
2760 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
2761 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
2762 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002763
Yun Parkbaa62862017-01-18 13:43:34 -08002764 cdp_ipa_set_doorbell_paddr(soc, (void *)pdev,
2765 ipa_ctxt->tx_comp_doorbell_paddr,
2766 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002767
Yun Parkbaa62862017-01-18 13:43:34 -08002768 cdp_ipa_register_op_cb(soc, (void *)pdev,
2769 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
2770
2771 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2772 "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x",
2773 pdev->ipa_uc_op_cb,
2774 (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr,
2775 (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002776
2777 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08002778 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Yun Parkbaa62862017-01-18 13:43:34 -08002779 hdd_ipa_uc_fw_op_event_handler);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002780 ipa_ctxt->uc_op_work[i].msg = NULL;
2781 }
2782
Yun Parkbaa62862017-01-18 13:43:34 -08002783fail_return:
2784 EXIT();
2785 return stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002786}
2787
Leo Change3e49442015-10-26 20:07:13 -07002788/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002789 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002790 * @hdd_ctx: hdd main context
2791 *
2792 * Force shutdown IPA pipe
2793 * Independent of FW pipe status, IPA pipe shutdonw progress
2794 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2795 * independent from FW pipe status
2796 *
2797 * Return: NONE
2798 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002799static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002800{
2801 struct hdd_ipa_priv *hdd_ipa;
2802
2803 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2804 return;
2805
2806 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2807 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302808 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07002809 "IPA pipes are not down yet, force shutdown");
2810 hdd_ipa_uc_disable_pipes(hdd_ipa);
2811 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002812 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Leo Change3e49442015-10-26 20:07:13 -07002813 "IPA pipes are down, do nothing");
2814 }
2815
2816 return;
2817}
2818
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002819/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002820 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2821 * __hdd_ipa_uc_force_pipe_shutdown
2822 * @hdd_ctx: hdd main context
2823 *
2824 * Force shutdown IPA pipe
2825 * Independent of FW pipe status, IPA pipe shutdonw progress
2826 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2827 * independent from FW pipe status
2828 *
2829 * Return: NONE
2830 */
2831void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2832{
2833 cds_ssr_protect(__func__);
2834 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2835 cds_ssr_unprotect(__func__);
2836}
2837
2838/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302839 * hdd_ipa_msg_free_fn() - Free an IPA message
2840 * @buff: pointer to the IPA message
2841 * @len: length of the IPA message
2842 * @type: type of IPA message
2843 *
2844 * Return: None
2845 */
2846static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2847{
Srinivas Girigowda97852372017-03-06 16:52:59 -08002848 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05302849 ghdd_ipa->stats.num_free_msg++;
2850 qdf_mem_free(buff);
2851}
2852
Govind Singh9c58eba2016-09-02 16:23:06 +05302853/**
jge62037862016-12-09 10:44:33 +08002854 * hdd_ipa_uc_send_evt() - send event to ipa
2855 * @hdd_ctx: pointer to hdd context
2856 * @type: event type
2857 * @mac_addr: pointer to mac address
2858 *
2859 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05302860 *
2861 * Return: 0 - Success
2862 */
jge62037862016-12-09 10:44:33 +08002863static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
2864 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05302865{
jge62037862016-12-09 10:44:33 +08002866 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05302867 struct ipa_msg_meta meta;
2868 struct ipa_wlan_msg *msg;
2869 int ret = 0;
jge62037862016-12-09 10:44:33 +08002870
2871 meta.msg_len = sizeof(struct ipa_wlan_msg);
2872 msg = qdf_mem_malloc(meta.msg_len);
2873 if (msg == NULL) {
2874 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2875 "msg allocation failed");
2876 return -ENOMEM;
2877 }
2878
2879 meta.msg_type = type;
2880 strlcpy(msg->name, adapter->dev->name,
2881 IPA_RESOURCE_NAME_MAX);
2882 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002883 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
jge62037862016-12-09 10:44:33 +08002884 msg->name, meta.msg_type);
2885 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2886 if (ret) {
2887 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2888 "%s: Evt: %d fail:%d",
2889 msg->name, meta.msg_type, ret);
2890 qdf_mem_free(msg);
2891 return ret;
2892 }
2893
2894 hdd_ipa->stats.num_send_msg++;
2895
2896 return ret;
2897}
2898
2899/**
2900 * hdd_ipa_uc_disconnect_client() - send client disconnect event
2901 * @hdd_ctx: pointer to hdd adapter
2902 *
2903 * Send disconnect client event to IPA driver during SSR
2904 *
2905 * Return: 0 - Success
2906 */
2907static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
2908{
2909 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2910 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05302911 int i;
2912
2913 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2914 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2915 continue;
2916 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08002917 (!adapter->aStaInfo[i].isDeauthInProgress) &&
2918 hdd_ipa->sap_num_connected_sta) {
2919 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
2920 adapter->aStaInfo[i].macAddrSTA.bytes);
2921 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05302922 }
2923 }
2924
2925 return ret;
2926}
2927
2928/**
jge62037862016-12-09 10:44:33 +08002929 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
2930 * @hdd_ctx: pointer to hdd adapter
2931 *
2932 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05302933 *
2934 * Return: 0 - Success
2935 */
jge62037862016-12-09 10:44:33 +08002936
2937static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
2938{
2939 int ret = 0;
2940
2941 if (adapter->ipa_context)
2942 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
2943 adapter->dev->dev_addr);
2944
2945 return ret;
2946}
2947
jge62037862016-12-09 10:44:33 +08002948/**
2949 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
2950 * @hdd_ctx: pointer to hdd adapter
2951 *
2952 * Send disconnect sta event to IPA driver during SSR
2953 *
2954 * Return: 0 - Success
2955 */
2956static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2957{
2958 hdd_station_ctx_t *pHddStaCtx;
2959 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2960 int ret = 0;
2961
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002962 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08002963 hdd_ipa->sta_connected) {
2964 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2965 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002966 pHddStaCtx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08002967 }
2968
2969 return ret;
2970}
jge62037862016-12-09 10:44:33 +08002971
2972/**
2973 * hdd_ipa_uc_disconnect() - send disconnect ipa event
2974 * @hdd_ctx: pointer to hdd context
2975 *
2976 * Send disconnect event to IPA driver during SSR
2977 *
2978 * Return: 0 - Success
2979 */
2980static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05302981{
2982 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2983 QDF_STATUS status;
2984 hdd_adapter_t *adapter;
2985 int ret = 0;
2986
Govind Singh9c58eba2016-09-02 16:23:06 +05302987 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2988 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2989 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08002990 if (adapter->device_mode == QDF_SAP_MODE) {
2991 hdd_ipa_uc_disconnect_client(adapter);
2992 hdd_ipa_uc_disconnect_ap(adapter);
2993 } else if (adapter->device_mode == QDF_STA_MODE) {
2994 hdd_ipa_uc_disconnect_sta(adapter);
2995 }
2996
Govind Singh9c58eba2016-09-02 16:23:06 +05302997 status = hdd_get_next_adapter(
2998 hdd_ctx, adapter_node, &next);
2999 adapter_node = next;
3000 }
3001
3002 return ret;
3003}
3004
3005/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003006 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003007 *
3008 * Deinit basic IPA UC host side to be in sync reloaded FW during
3009 * SSR
3010 *
3011 * Return: 0 - Success
3012 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003013static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014{
3015 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3016 int idx;
3017 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303018 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003019
Arun Khandavallicc544b32017-01-30 19:52:16 +05303020 if (!hdd_ipa)
3021 return 0;
3022
3023 hdd_ctx = hdd_ipa->hdd_ctx;
3024 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003025 return 0;
3026
jge62037862016-12-09 10:44:33 +08003027 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303028 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003029
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003030 /* Clean up HDD IPA interfaces */
3031 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3032 (idx < HDD_IPA_MAX_IFACE); idx++) {
3033 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003034 if (iface_context->adapter && iface_context->adapter->magic ==
3035 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003036 hdd_ipa_cleanup_iface(iface_context);
3037 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003038 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003039 /* After SSR, wlan driver reloads FW again. But we need to protect
3040 * IPA submodule during SSR transient state. So deinit basic IPA
3041 * UC host side to be in sync with reloaded FW during SSR
3042 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08003043 if (!hdd_ipa->ipa_pipes_down)
3044 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003045
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303046 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003047 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3048 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3049 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3050 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303051 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003052
Srinivas Girigowda97852372017-03-06 16:52:59 -08003053 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Arun Khandavallicc544b32017-01-30 19:52:16 +05303054 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
3055 __func__, hdd_ipa->tx_pipe_handle);
3056 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
3057
Srinivas Girigowda97852372017-03-06 16:52:59 -08003058 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Arun Khandavallicc544b32017-01-30 19:52:16 +05303059 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
3060 __func__, hdd_ipa->rx_pipe_handle);
3061 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
3062
Guolei Bianca144d82016-11-10 11:07:42 +08003063 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3064 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3065
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003066 /* Full IPA driver cleanup not required since wlan driver is now
3067 * unloaded and reloaded after SSR.
3068 */
3069 return 0;
3070}
3071
3072/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003073 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3074 *
3075 * Deinit basic IPA UC host side to be in sync reloaded FW during
3076 * SSR
3077 *
3078 * Return: 0 - Success
3079 */
3080int hdd_ipa_uc_ssr_deinit(void)
3081{
3082 int ret;
3083
3084 cds_ssr_protect(__func__);
3085 ret = __hdd_ipa_uc_ssr_deinit();
3086 cds_ssr_unprotect(__func__);
3087
3088 return ret;
3089}
3090
3091/**
3092 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003093 *
3094 * Init basic IPA UC host side to be in sync with reloaded FW after
3095 * SSR to resume IPA UC operations
3096 *
3097 * Return: 0 - Success
3098 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303099static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003100{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101
Arun Khandavallicc544b32017-01-30 19:52:16 +05303102 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3103 int i;
3104 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303105
3106 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3107 return 0;
3108
Arun Khandavallicc544b32017-01-30 19:52:16 +05303109 /* Create the interface context */
3110 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3111 iface_context = &hdd_ipa->iface_context[i];
3112 iface_context->hdd_ipa = hdd_ipa;
3113 iface_context->cons_client =
3114 hdd_ipa_adapter_2_client[i].cons_client;
3115 iface_context->prod_client =
3116 hdd_ipa_adapter_2_client[i].prod_client;
3117 iface_context->iface_id = i;
3118 iface_context->adapter = NULL;
3119 }
3120 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3121 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3122 hdd_ipa->vdev_offload_enabled[i] = false;
3123 }
3124
3125 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3126 hdd_ipa->resource_loading = false;
3127 hdd_ipa->resource_unloading = false;
3128 hdd_ipa->sta_connected = 0;
3129 hdd_ipa->ipa_pipes_down = true;
3130 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303131 }
3132
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003133 return 0;
3134}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003135
3136/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003137 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3138 *
3139 * Init basic IPA UC host side to be in sync with reloaded FW after
3140 * SSR to resume IPA UC operations
3141 *
3142 * Return: 0 - Success
3143 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303144int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003145{
3146 int ret;
3147
3148 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303149 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003150 cds_ssr_unprotect(__func__);
3151
3152 return ret;
3153}
3154
3155/**
3156 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08003157 * @hdd_ctx: Global HDD context
3158 * @skb: skb sent to IPA
3159 * @session_id: send packet instance session id
3160 *
3161 * Send TX packet which generated by system to IPA.
3162 * This routine only will be used for function verification
3163 *
3164 * Return: NULL packet sent to IPA properly
3165 * NULL invalid packet drop
3166 * skb packet not sent to IPA. legacy data path should handle
3167 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003168static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08003169 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07003170{
Leo Chang3bc8fed2015-11-13 10:59:47 -08003171 struct ipa_header *ipa_header;
3172 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003173 struct hdd_ipa_priv *hdd_ipa;
3174
3175 if (wlan_hdd_validate_context(hdd_ctx))
3176 return skb;
3177
3178 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003179
3180 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3181 return skb;
3182
Leo Chang07b28f62016-05-11 12:29:22 -07003183 if (!hdd_ipa)
3184 return skb;
3185
3186 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
3187 return skb;
3188
Leo Changcc923e22016-06-16 15:29:03 -07003189 if (skb_headroom(skb) <
3190 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07003191 return skb;
3192
Leo Chang3bc8fed2015-11-13 10:59:47 -08003193 ipa_header = (struct ipa_header *) skb_push(skb,
3194 sizeof(struct ipa_header));
3195 if (!ipa_header) {
3196 /* No headroom, legacy */
3197 return skb;
3198 }
3199 memset(ipa_header, 0, sizeof(*ipa_header));
3200 ipa_header->vdev_id = 0;
3201
3202 frag_header = (struct frag_header *) skb_push(skb,
3203 sizeof(struct frag_header));
3204 if (!frag_header) {
3205 /* No headroom, drop */
3206 kfree_skb(skb);
3207 return NULL;
3208 }
3209 memset(frag_header, 0, sizeof(*frag_header));
3210 frag_header->length = skb->len - sizeof(struct frag_header)
3211 - sizeof(struct ipa_header);
3212
3213 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
3214 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07003215}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003216
3217/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003218 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
3219 * @hdd_ctx: Global HDD context
3220 * @skb: skb sent to IPA
3221 * @session_id: send packet instance session id
3222 *
3223 * Send TX packet which generated by system to IPA.
3224 * This routine only will be used for function verification
3225 *
3226 * Return: NULL packet sent to IPA properly
3227 * NULL invalid packet drop
3228 * skb packet not sent to IPA. legacy data path should handle
3229 */
3230struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
3231 struct sk_buff *skb, uint8_t session_id)
3232{
3233 struct sk_buff *ret;
3234
3235 cds_ssr_protect(__func__);
3236 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
3237 cds_ssr_unprotect(__func__);
3238
3239 return ret;
3240}
3241
3242/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003243 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3244 * @work: scheduled work
3245 *
3246 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3247 * not want to immediately release the wake lock since the system
3248 * would then potentially try to suspend when there is a healthy data
3249 * rate. Deferred work is scheduled and this function handles the
3250 * work. When this function is called, if the IPA resource is still
3251 * released then we release the wake lock.
3252 *
3253 * Return: None
3254 */
3255static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3256{
3257 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3258 struct hdd_ipa_priv,
3259 wake_lock_work);
3260
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303261 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003262
3263 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3264 goto end;
3265
3266 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303267 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003268 WIFI_POWER_EVENT_WAKELOCK_IPA);
3269
3270end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303271 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272}
3273
3274/**
3275 * hdd_ipa_rm_request() - Request resource from IPA
3276 * @hdd_ipa: Global HDD IPA context
3277 *
3278 * Return: 0 on success, negative errno on error
3279 */
3280static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3281{
3282 int ret = 0;
3283
3284 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3285 return 0;
3286
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303287 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003288
3289 switch (hdd_ipa->rm_state) {
3290 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303291 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003292 return 0;
3293 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303294 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003295 return -EINPROGRESS;
3296 case HDD_IPA_RM_RELEASED:
3297 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3298 break;
3299 }
3300
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303301 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003302
3303 ret = ipa_rm_inactivity_timer_request_resource(
3304 IPA_RM_RESOURCE_WLAN_PROD);
3305
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303306 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003307 if (ret == 0) {
3308 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3309 hdd_ipa->stats.num_rm_grant_imm++;
3310 }
3311
3312 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3313 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303314 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003315 WIFI_POWER_EVENT_WAKELOCK_IPA);
3316 hdd_ipa->wake_lock_released = false;
3317 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303318 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003319
3320 return ret;
3321}
3322
3323/**
3324 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3325 * @hdd_ipa: Global HDD IPA context
3326 *
3327 * Return: 0 if resources released, negative errno otherwise
3328 */
3329static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3330{
3331 int ret = 0;
3332
3333 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3334 return 0;
3335
3336 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3337 return -EAGAIN;
3338
3339 spin_lock_bh(&hdd_ipa->q_lock);
3340 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
3341 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
3342 spin_unlock_bh(&hdd_ipa->q_lock);
3343 return -EAGAIN;
3344 }
3345 spin_unlock_bh(&hdd_ipa->q_lock);
3346
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303347 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003348
Nirav Shahcbc6d722016-03-01 16:24:53 +05303349 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303350 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003351 return -EAGAIN;
3352 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303353 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003354
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303355 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003356 switch (hdd_ipa->rm_state) {
3357 case HDD_IPA_RM_GRANTED:
3358 break;
3359 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303360 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003361 return -EINPROGRESS;
3362 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303363 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364 return 0;
3365 }
3366
3367 /* IPA driver returns immediately so set the state here to avoid any
3368 * race condition.
3369 */
3370 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3371 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303372 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003373
3374 ret =
3375 ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
3376
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303377 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003378 if (unlikely(ret != 0)) {
3379 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3380 WARN_ON(1);
3381 }
3382
3383 /*
3384 * If wake_lock is released immediately, kernel would try to suspend
3385 * immediately as well, Just avoid ping-pong between suspend-resume
3386 * while there is healthy amount of data transfer going on by
3387 * releasing the wake_lock after some delay.
3388 */
3389 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3390 msecs_to_jiffies
3391 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3392
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303393 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003394
3395 return ret;
3396}
3397
3398/**
3399 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3400 * @user_data: user data registered with IPA
3401 * @event: the IPA resource manager event that occurred
3402 * @data: the data associated with the event
3403 *
3404 * Return: None
3405 */
3406static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3407 unsigned long data)
3408{
3409 struct hdd_ipa_priv *hdd_ipa = user_data;
3410
3411 if (unlikely(!hdd_ipa))
3412 return;
3413
3414 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3415 return;
3416
Srinivas Girigowda97852372017-03-06 16:52:59 -08003417 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418
3419 switch (event) {
3420 case IPA_RM_RESOURCE_GRANTED:
3421 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3422 /* RM Notification comes with ISR context
3423 * it should be serialized into work queue to avoid
3424 * ISR sleep problem
3425 */
3426 hdd_ipa->uc_rm_work.event = event;
3427 schedule_work(&hdd_ipa->uc_rm_work.work);
3428 break;
3429 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303430 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003431 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303432 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433 hdd_ipa->stats.num_rm_grant++;
3434 break;
3435
3436 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003437 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003438 hdd_ipa->resource_unloading = false;
3439 break;
3440
3441 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303442 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003443 break;
3444 }
3445}
3446
3447/**
3448 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3449 *
3450 * Callback function registered with IPA that is called when IPA wants
3451 * to release the WLAN consumer resource
3452 *
3453 * Return: 0 if the request is granted, negative errno otherwise
3454 */
3455static int hdd_ipa_rm_cons_release(void)
3456{
3457 return 0;
3458}
3459
3460/**
3461 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3462 *
3463 * Callback function registered with IPA that is called when IPA wants
3464 * to access the WLAN consumer resource
3465 *
3466 * Return: 0 if the request is granted, negative errno otherwise
3467 */
3468static int hdd_ipa_rm_cons_request(void)
3469{
Yun Park4d8b60a2015-10-22 13:59:32 -07003470 int ret = 0;
3471
3472 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303473 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003474 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003475 __func__);
3476 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003477 ret = -EINPROGRESS;
3478 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303479 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003480 "%s: IPA resource unloading in progress",
3481 __func__);
3482 ghdd_ipa->pending_cons_req = true;
3483 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003484 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003485
3486 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003487}
3488
3489/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003490 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003491 * @hdd_ctx: Global HDD context
3492 * @tx_packets: Number of packets transmitted in the last sample period
3493 * @rx_packets: Number of packets received in the last sample period
3494 *
3495 * Return: 0 on success, negative errno on error
3496 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003497static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003498 uint64_t rx_packets)
3499{
3500 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003501 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003502 struct ipa_rm_perf_profile profile;
3503 int ret;
3504
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003505 if (wlan_hdd_validate_context(hdd_ctx))
3506 return 0;
3507
3508 hdd_ipa = hdd_ctx->hdd_ipa;
3509
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003510 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3511 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3512 return 0;
3513
3514 memset(&profile, 0, sizeof(profile));
3515
3516 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3517 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3518 else if (tx_packets >
3519 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3520 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3521 else
3522 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3523
3524 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3525 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3526 else if (rx_packets >
3527 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3528 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3529 else
3530 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3531
Yun Parkec845302016-12-15 09:22:57 -08003532 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003533 "CONS perf curr: %d, next: %d",
3534 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003535 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003536 "PROD perf curr: %d, next: %d",
3537 hdd_ipa->curr_prod_bw, next_prod_bw);
3538
3539 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003540 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003541 hdd_ipa->curr_cons_bw, next_cons_bw);
3542 profile.max_supported_bandwidth_mbps = next_cons_bw;
3543 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3544 &profile);
3545 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003546 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003547
3548 return ret;
3549 }
3550 hdd_ipa->curr_cons_bw = next_cons_bw;
3551 hdd_ipa->stats.num_cons_perf_req++;
3552 }
3553
3554 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003555 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003556 hdd_ipa->curr_prod_bw, next_prod_bw);
3557 profile.max_supported_bandwidth_mbps = next_prod_bw;
3558 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3559 &profile);
3560 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003561 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003562 return ret;
3563 }
3564 hdd_ipa->curr_prod_bw = next_prod_bw;
3565 hdd_ipa->stats.num_prod_perf_req++;
3566 }
3567
3568 return 0;
3569}
3570
3571/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003572 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3573 * @hdd_ctx: Global HDD context
3574 * @tx_packets: Number of packets transmitted in the last sample period
3575 * @rx_packets: Number of packets received in the last sample period
3576 *
3577 * Return: 0 on success, negative errno on error
3578 */
3579int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3580 uint64_t rx_packets)
3581{
3582 int ret;
3583
3584 cds_ssr_protect(__func__);
3585 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3586 cds_ssr_unprotect(__func__);
3587
3588 return ret;
3589}
3590
3591/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003592 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3593 * @work: struct work_struct
3594 * @work_handler: work_handler
3595 *
3596 * Return: none
3597 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003598static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3599 work_func_t work_handler)
3600{
3601 INIT_WORK(work, work_handler);
3602}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003603
3604/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003605 * hdd_ipa_setup_rm() - Setup IPA resource management
3606 * @hdd_ipa: Global HDD IPA context
3607 *
3608 * Return: 0 on success, negative errno on error
3609 */
3610static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3611{
3612 struct ipa_rm_create_params create_params = { 0 };
3613 int ret;
3614
3615 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3616 return 0;
3617
Rajeev Kumar217f2172016-01-06 18:11:55 -08003618 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3619 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003620 memset(&create_params, 0, sizeof(create_params));
3621 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3622 create_params.reg_params.user_data = hdd_ipa;
3623 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3624 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3625
3626 ret = ipa_rm_create_resource(&create_params);
3627 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303628 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003629 "Create RM resource failed: %d", ret);
3630 goto setup_rm_fail;
3631 }
3632
3633 memset(&create_params, 0, sizeof(create_params));
3634 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3635 create_params.request_resource = hdd_ipa_rm_cons_request;
3636 create_params.release_resource = hdd_ipa_rm_cons_release;
3637 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3638
3639 ret = ipa_rm_create_resource(&create_params);
3640 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303641 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003642 "Create RM CONS resource failed: %d", ret);
3643 goto delete_prod;
3644 }
3645
3646 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3647 IPA_RM_RESOURCE_APPS_CONS);
3648
3649 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3650 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3651 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303652 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003653 ret);
3654 goto timer_init_failed;
3655 }
3656
3657 /* Set the lowest bandwidth to start with */
3658 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3659
3660 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303661 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003662 "Set perf level failed: %d", ret);
3663 goto set_perf_failed;
3664 }
3665
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303666 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003667 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3668 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303669 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003670 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3671 hdd_ipa->wake_lock_released = true;
3672 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3673
3674 return ret;
3675
3676set_perf_failed:
3677 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3678
3679timer_init_failed:
3680 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3681
3682delete_prod:
3683 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3684
3685setup_rm_fail:
3686 return ret;
3687}
3688
3689/**
3690 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3691 * @hdd_ipa: Global HDD IPA context
3692 *
3693 * Destroys all resources associated with the IPA resource manager
3694 *
3695 * Return: None
3696 */
3697static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3698{
3699 int ret;
3700
3701 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3702 return;
3703
3704 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303705 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003706
3707#ifdef WLAN_OPEN_SOURCE
3708 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
3709#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303710 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003711
3712 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3713
3714 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3715 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303716 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003717 "RM PROD resource delete failed %d", ret);
3718
3719 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3720 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303721 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003722 "RM CONS resource delete failed %d", ret);
3723}
3724
3725/**
3726 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3727 * @skb: network buffer
3728 * @adapter: network adapter
3729 *
3730 * Called when a network buffer is received which should not be routed
3731 * to the IPA module.
3732 *
3733 * Return: None
3734 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303735static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003736 hdd_adapter_t *adapter)
3737{
3738 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3739 unsigned int cpu_index;
3740
3741 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003742 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003743 adapter);
3744 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003745 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003746 return;
3747 }
3748
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003749 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003750 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003751 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003752 return;
3753 }
3754
3755 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3756 skb->dev = adapter->dev;
3757 skb->protocol = eth_type_trans(skb, skb->dev);
3758 skb->ip_summed = CHECKSUM_NONE;
3759
3760 cpu_index = wlan_hdd_get_cpu();
3761
3762 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
3763 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
3764 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3765 else
3766 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3767
3768 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
3769 adapter->dev->last_rx = jiffies;
3770}
3771
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003772/**
Leo Chang69c39692016-10-12 20:11:12 -07003773 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3774 * @hdd_ipa: pointer to hdd ipa context
3775 * @adapter: network adapter
3776 * @skb: data pointer
3777 *
3778 * if exception packet has set forward bit, copied new packet should be
3779 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3780 * put into pm queue and tx procedure will be differed
3781 *
3782 * Return: None
3783 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003784static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
3785 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003786{
Leo Chang69c39692016-10-12 20:11:12 -07003787 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3788
Leo Chang69c39692016-10-12 20:11:12 -07003789 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
3790 /* WLAN subsystem is in suspend, put int queue */
3791 if (hdd_ipa->suspended) {
3792 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3793 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3794 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003795 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3796 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003797 pm_tx_cb->exception = true;
3798 pm_tx_cb->adapter = adapter;
3799 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003800 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003801 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3802 hdd_ipa->stats.num_tx_queued++;
3803 } else {
3804 /* Resume, put packet into WLAN TX */
3805 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003806 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003807 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3808 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003809 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003810 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003811 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003812 hdd_ipa->ipa_tx_forward++;
3813 }
3814 }
3815}
3816
3817/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003818 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3819 * @hdd_ipa: pointer to HDD IPA struct
3820 * @adapter: hdd adapter pointer
3821 * @desc: Firmware descriptor
3822 * @skb: Data buffer
3823 *
3824 * Return:
3825 * HDD_IPA_FORWARD_PKT_NONE
3826 * HDD_IPA_FORWARD_PKT_DISCARD
3827 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3828 *
3829 */
3830
3831static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3832 struct hdd_ipa_priv *hdd_ipa,
3833 hdd_adapter_t *adapter,
3834 uint8_t desc,
3835 qdf_nbuf_t skb)
3836{
3837 int ret = HDD_IPA_FORWARD_PKT_NONE;
3838
3839 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303840 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003841 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
3842 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303843 /* Drop the packet*/
3844 hdd_ipa->stats.num_tx_fwd_err++;
3845 kfree_skb(skb);
3846 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3847 return ret;
3848 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003849 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3850 "Forward packet to Tx (fw_desc=%d)", desc);
3851 hdd_ipa->ipa_tx_forward++;
3852
3853 if ((desc & FW_RX_DESC_DISCARD_M)) {
3854 hdd_ipa_forward(hdd_ipa, adapter, skb);
3855 hdd_ipa->ipa_rx_internel_drop_count++;
3856 hdd_ipa->ipa_rx_discard++;
3857 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3858 } else {
3859 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
3860 if (cloned_skb)
3861 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3862 else
3863 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3864 "%s: tx skb alloc failed",
3865 __func__);
3866 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3867 }
3868 }
3869
3870 return ret;
3871}
3872
3873/**
Leo Chang69c39692016-10-12 20:11:12 -07003874 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003875 * @priv: pointer to private data registered with IPA (we register a
3876 * pointer to the global IPA context)
3877 * @evt: the IPA event which triggered the callback
3878 * @data: data associated with the event
3879 *
3880 * Return: None
3881 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003882static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003883 unsigned long data)
3884{
3885 struct hdd_ipa_priv *hdd_ipa = NULL;
3886 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303887 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003888 uint8_t iface_id;
3889 uint8_t session_id;
3890 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003891 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003892 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003893
3894 hdd_ipa = (struct hdd_ipa_priv *)priv;
3895
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003896 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3897 return;
3898
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003899 switch (evt) {
3900 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303901 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003902
3903 /*
3904 * When SSR is going on or driver is unloading,
3905 * just drop the packets.
3906 */
3907 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
3908 if (0 != status) {
3909 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3910 "Invalid context: drop packet");
3911 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3912 kfree_skb(skb);
3913 return;
3914 }
3915
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003916 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3917 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003918 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08003919 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003920 "IPA_RECEIVE: session_id=%u, iface_id=%u",
3921 session_id, iface_id);
3922 } else {
3923 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
3924 }
3925
3926 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303927 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003928 "IPA_RECEIVE: Invalid iface_id: %u",
3929 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003930 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003931 "w2i -- skb",
3932 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003933 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003934 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003935 return;
3936 }
3937
3938 iface_context = &hdd_ipa->iface_context[iface_id];
3939 adapter = iface_context->adapter;
3940
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303941 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003942 "w2i -- skb",
3943 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003944 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3945 hdd_ipa->stats.num_rx_excep++;
3946 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
3947 } else {
3948 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
3949 }
3950
3951 iface_context->stats.num_rx_ipa_excep++;
3952
3953 /* Disable to forward Intra-BSS Rx packets when
3954 * ap_isolate=1 in hostapd.conf
3955 */
Yun Park046101c2016-09-02 15:32:14 -07003956 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003957 /*
3958 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3959 * all Rx packets to IPA uC, which need to be forwarded
3960 * to other interface.
3961 * And, IPA driver will send back to WLAN host driver
3962 * through exception pipe with fw_desc field set by FW.
3963 * Here we are checking fw_desc field for FORWARD bit
3964 * set, and forward to Tx. Then copy to kernel stack
3965 * only when DISCARD bit is not set.
3966 */
3967 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003968 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3969 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3970 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003971 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003972 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003973 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003974 "Intra-BSS FWD is disabled-skip forward to Tx");
3975 }
3976
3977 hdd_ipa_send_skb_to_network(skb, adapter);
3978 break;
3979
3980 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303981 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982 "w2i cb wrong event: 0x%x", evt);
3983 return;
3984 }
3985}
3986
3987/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003988 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3989 * @priv: pointer to private data registered with IPA (we register a
3990 * pointer to the global IPA context)
3991 * @evt: the IPA event which triggered the callback
3992 * @data: data associated with the event
3993 *
3994 * Return: None
3995 */
3996static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3997 unsigned long data)
3998{
3999 cds_ssr_protect(__func__);
4000 __hdd_ipa_w2i_cb(priv, evt, data);
4001 cds_ssr_unprotect(__func__);
4002}
4003
4004/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004005 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4006 * @skb: packet buffer which was transmitted
4007 *
4008 * Return: None
4009 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304010void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004011{
4012 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4013
Govind Singhb6a89772016-08-12 11:23:35 +05304014 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05304015 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004016 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304017 ipa_free_skb((struct ipa_rx_data *)
4018 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004019
4020 hdd_ipa->stats.num_tx_comp_cnt++;
4021
4022 atomic_dec(&hdd_ipa->tx_ref_cnt);
4023
4024 hdd_ipa_rm_try_release(hdd_ipa);
4025}
4026
4027/**
4028 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4029 * @iface_context: interface-specific IPA context
4030 * @ipa_tx_desc: packet data descriptor
4031 *
4032 * Return: None
4033 */
4034static void hdd_ipa_send_pkt_to_tl(
4035 struct hdd_ipa_iface_context *iface_context,
4036 struct ipa_rx_data *ipa_tx_desc)
4037{
4038 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004039 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304040 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004041
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304042 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004043 adapter = iface_context->adapter;
4044 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304045 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004046 ipa_free_skb(ipa_tx_desc);
4047 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304048 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004049 hdd_ipa_rm_try_release(hdd_ipa);
4050 return;
4051 }
4052
4053 /*
4054 * During CAC period, data packets shouldn't be sent over the air so
4055 * drop all the packets here
4056 */
4057 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4058 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304059 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004060 iface_context->stats.num_tx_cac_drop++;
4061 hdd_ipa_rm_try_release(hdd_ipa);
4062 return;
4063 }
4064
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004065 ++adapter->stats.tx_packets;
4066
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304067 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004068
4069 skb = ipa_tx_desc->skb;
4070
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304071 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304072 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004073 /* FIXME: This is broken. No such field in cb any more:
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08004074 * NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb;
4075 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004076 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304077 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004078 ipa_tx_desc->dma_addr
4079 + HDD_IPA_WLAN_FRAG_HEADER
4080 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004081 ipa_tx_desc->skb->len -=
4082 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4083 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304084 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004085
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004086 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304087 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004088
4089 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
4090
Leo Changfdb45c32016-10-28 11:09:23 -07004091 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004092 (struct cdp_vdev *)iface_context->tl_context,
4093 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004094 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304095 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004096 ipa_free_skb(ipa_tx_desc);
4097 iface_context->stats.num_tx_err++;
4098 hdd_ipa_rm_try_release(hdd_ipa);
4099 return;
4100 }
4101
4102 atomic_inc(&hdd_ipa->tx_ref_cnt);
4103
4104 iface_context->stats.num_tx++;
4105
4106}
4107
4108/**
Leo Chang11545d62016-10-17 14:53:50 -07004109 * hdd_ipa_is_present() - get IPA hw status
4110 * @hdd_ctx: pointer to hdd context
4111 *
4112 * ipa_uc_reg_rdyCB is not directly designed to check
4113 * ipa hw status. This is an undocumented function which
4114 * has confirmed with IPA team.
4115 *
4116 * Return: true - ipa hw present
4117 * false - ipa hw not present
4118 */
4119bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
4120{
4121 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004122 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004123 return true;
4124 else
4125 return false;
4126}
4127
4128/**
Leo Chang69c39692016-10-12 20:11:12 -07004129 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004130 * @work: pointer to the scheduled work
4131 *
4132 * Called during PM resume to send packets to TL which were queued
4133 * while host was in the process of suspending.
4134 *
4135 * Return: None
4136 */
Leo Chang69c39692016-10-12 20:11:12 -07004137static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004138{
4139 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4140 struct hdd_ipa_priv,
4141 pm_work);
4142 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304143 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004144 uint32_t dequeued = 0;
4145
Leo Chang69c39692016-10-12 20:11:12 -07004146 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4147 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304148 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304149 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4150 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304151 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004152
4153 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004154 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004155 if (pm_tx_cb->exception) {
4156 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4157 "FLUSH EXCEPTION");
4158 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
4159 } else {
4160 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004161 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004162 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304163 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004164 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304165 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004166 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4167 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004168
4169 hdd_ipa->stats.num_tx_dequeued += dequeued;
4170 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4171 hdd_ipa->stats.num_max_pm_queue = dequeued;
4172}
4173
4174/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004175 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004176 * @priv: pointer to private data registered with IPA (we register a
4177 * pointer to the interface-specific IPA context)
4178 * @evt: the IPA event which triggered the callback
4179 * @data: data associated with the event
4180 *
4181 * Return: None
4182 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004183static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004184 unsigned long data)
4185{
4186 struct hdd_ipa_priv *hdd_ipa = NULL;
4187 struct ipa_rx_data *ipa_tx_desc;
4188 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304189 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304191 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004192
Mukul Sharma81661ae2015-10-30 20:26:02 +05304193 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004194 ipa_tx_desc = (struct ipa_rx_data *)data;
4195 hdd_ipa = iface_context->hdd_ipa;
4196
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004197 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004198 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4199 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004200 iface_context->stats.num_tx_drop++;
4201 return;
4202 }
4203
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004204 /*
4205 * When SSR is going on or driver is unloading, just drop the packets.
4206 * During SSR, there is no use in queueing the packets as STA has to
4207 * connect back any way
4208 */
4209 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304210 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004211 ipa_free_skb(ipa_tx_desc);
4212 iface_context->stats.num_tx_drop++;
4213 return;
4214 }
4215
4216 skb = ipa_tx_desc->skb;
4217
Yun Parkb187d542016-11-14 18:10:04 -08004218 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4219 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004220
4221 /*
4222 * If PROD resource is not requested here then there may be cases where
4223 * IPA hardware may be clocked down because of not having proper
4224 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4225 * workaround to request PROD resource while data is going over CONS
4226 * pipe to prevent the IPA hardware clockdown.
4227 */
4228 hdd_ipa_rm_request(hdd_ipa);
4229
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304230 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004231 /*
4232 * If host is still suspended then queue the packets and these will be
4233 * drained later when resume completes. When packet is arrived here and
4234 * host is suspended, this means that there is already resume is in
4235 * progress.
4236 */
4237 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304238 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004239 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4240 pm_tx_cb->iface_context = iface_context;
4241 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304242 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004243 hdd_ipa->stats.num_tx_queued++;
4244
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304245 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004246 return;
4247 }
4248
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304249 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004250
4251 /*
4252 * If we are here means, host is not suspended, wait for the work queue
4253 * to finish.
4254 */
4255#ifdef WLAN_OPEN_SOURCE
4256 flush_work(&hdd_ipa->pm_work);
4257#endif
4258
4259 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4260}
4261
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004262/*
4263 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4264 * @priv: pointer to private data registered with IPA (we register a
4265 * pointer to the interface-specific IPA context)
4266 * @evt: the IPA event which triggered the callback
4267 * @data: data associated with the event
4268 *
4269 * Return: None
4270 */
4271static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
4272 unsigned long data)
4273{
4274 cds_ssr_protect(__func__);
4275 __hdd_ipa_i2w_cb(priv, evt, data);
4276 cds_ssr_unprotect(__func__);
4277}
4278
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004279/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004280 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004281 * @hdd_ctx: Global HDD context
4282 *
4283 * Return: 0 on success, negativer errno on error
4284 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004285static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004286{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004287 struct hdd_ipa_priv *hdd_ipa;
4288
4289 if (wlan_hdd_validate_context(hdd_ctx))
4290 return 0;
4291
4292 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293
4294 if (!hdd_ipa_is_enabled(hdd_ctx))
4295 return 0;
4296
4297 /*
4298 * Check if IPA is ready for suspend, If we are here means, there is
4299 * high chance that suspend would go through but just to avoid any race
4300 * condition after suspend started, these checks are conducted before
4301 * allowing to suspend.
4302 */
4303 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4304 return -EAGAIN;
4305
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304306 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004307
4308 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304309 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004310 return -EAGAIN;
4311 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304312 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004313
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304314 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004315 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304316 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004317
4318 return 0;
4319}
4320
4321/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004322 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4323 * @hdd_ctx: Global HDD context
4324 *
4325 * Return: 0 on success, negativer errno on error
4326 */
4327int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4328{
4329 int ret;
4330
4331 cds_ssr_protect(__func__);
4332 ret = __hdd_ipa_suspend(hdd_ctx);
4333 cds_ssr_unprotect(__func__);
4334
4335 return ret;
4336}
4337
4338/**
4339 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 * hdd_ctx: Global HDD context
4341 *
4342 * Return: 0 on success, negative errno on error
4343 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004344static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004345{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004346 struct hdd_ipa_priv *hdd_ipa;
4347
4348 if (wlan_hdd_validate_context(hdd_ctx))
4349 return 0;
4350
4351 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004352
4353 if (!hdd_ipa_is_enabled(hdd_ctx))
4354 return 0;
4355
4356 schedule_work(&hdd_ipa->pm_work);
4357
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304358 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004359 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304360 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004361
4362 return 0;
4363}
4364
4365/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004366 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4367 * hdd_ctx: Global HDD context
4368 *
4369 * Return: 0 on success, negative errno on error
4370 */
4371int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4372{
4373 int ret;
4374
4375 cds_ssr_protect(__func__);
4376 ret = __hdd_ipa_resume(hdd_ctx);
4377 cds_ssr_unprotect(__func__);
4378
4379 return ret;
4380}
4381
4382/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004383 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4384 * @hdd_ipa: Global HDD IPA context
4385 *
4386 * Return: 0 on success, negative errno on error
4387 */
4388static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4389{
4390 int i, ret = 0;
4391 struct ipa_sys_connect_params *ipa;
4392 uint32_t desc_fifo_sz;
4393
4394 /* The maximum number of descriptors that can be provided to a BAM at
4395 * once is one less than the total number of descriptors that the buffer
4396 * can contain.
4397 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4398 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4399 * be provided at once.
4400 * Because of above requirement, one extra descriptor will be added to
4401 * make sure hardware always has one descriptor.
4402 */
4403 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4404 + sizeof(struct sps_iovec);
4405
4406 /*setup TX pipes */
4407 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4408 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4409
4410 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4411 ipa->desc_fifo_sz = desc_fifo_sz;
4412 ipa->priv = &hdd_ipa->iface_context[i];
4413 ipa->notify = hdd_ipa_i2w_cb;
4414
4415 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4416 ipa->ipa_ep_cfg.hdr.hdr_len =
4417 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4418 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4419 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4420 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4421 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4422 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4423 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4424 } else {
4425 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4426 }
4427 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4428
4429 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4430 ipa->keep_ipa_awake = 1;
4431
4432 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4433 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304434 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004435 " ret: %d", i, ret);
4436 goto setup_sys_pipe_fail;
4437 }
4438 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4439 }
4440
4441 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4442 /*
4443 * Hard code it here, this can be extended if in case
4444 * PROD pipe is also per interface.
4445 * Right now there is no advantage of doing this.
4446 */
4447 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4448
4449 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4450
4451 ipa->client = hdd_ipa->prod_client;
4452
4453 ipa->desc_fifo_sz = desc_fifo_sz;
4454 ipa->priv = hdd_ipa;
4455 ipa->notify = hdd_ipa_w2i_cb;
4456
4457 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4458 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4459 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4460 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4461
4462 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4463 ipa->keep_ipa_awake = 1;
4464
4465 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4466 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304467 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468 "Failed for RX pipe: %d", ret);
4469 goto setup_sys_pipe_fail;
4470 }
4471 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4472 }
4473
4474 return ret;
4475
4476setup_sys_pipe_fail:
4477
4478 while (--i >= 0) {
4479 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304480 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004481 sizeof(struct hdd_ipa_sys_pipe));
4482 }
4483
4484 return ret;
4485}
4486
4487/**
4488 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4489 * @hdd_ipa: Global HDD IPA context
4490 *
4491 * Return: None
4492 */
4493static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4494{
4495 int ret = 0, i;
4496 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4497 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4498 ret =
4499 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4500 conn_hdl);
4501 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304502 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004503 ret);
4504
4505 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4506 }
4507 }
4508}
4509
4510/**
4511 * hdd_ipa_register_interface() - register IPA interface
4512 * @hdd_ipa: Global IPA context
4513 * @iface_context: Per-interface IPA context
4514 *
4515 * Return: 0 on success, negative errno on error
4516 */
4517static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
4518 struct hdd_ipa_iface_context
4519 *iface_context)
4520{
4521 struct ipa_tx_intf tx_intf;
4522 struct ipa_rx_intf rx_intf;
4523 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
4524 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
4525 char *ifname = iface_context->adapter->dev->name;
4526
4527 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
4528 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
4529
4530 int num_prop = 1;
4531 int ret = 0;
4532
4533 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
4534 num_prop++;
4535
4536 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
4537 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304538 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004539 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304540 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004541 goto register_interface_fail;
4542 }
4543
4544 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
4545 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304546 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004547 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304548 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004549 goto register_interface_fail;
4550 }
4551
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304552 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
4553 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004554
4555 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4556 ifname, HDD_IPA_IPV4_NAME_EXT);
4557 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4558 ifname, HDD_IPA_IPV6_NAME_EXT);
4559
4560 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4561 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
4562 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4563 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4564
4565 /*
4566 * Interface ID is 3rd byte in the CLD header. Add the meta data and
4567 * mask to identify the interface in IPA hardware
4568 */
4569 rx_prop[IPA_IP_v4].attrib.meta_data =
4570 htonl(iface_context->adapter->sessionId << 16);
4571 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4572
4573 rx_intf.num_props++;
4574 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4575 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4576 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
4577 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4578 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4579 rx_prop[IPA_IP_v4].attrib.meta_data =
4580 htonl(iface_context->adapter->sessionId << 16);
4581 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4582
4583 rx_intf.num_props++;
4584 }
4585
4586 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4587 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4588 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4589 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
4590 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
4591 IPA_RESOURCE_NAME_MAX);
4592 tx_intf.num_props++;
4593
4594 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4595 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4596 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4597 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4598 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
4599 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
4600 IPA_RESOURCE_NAME_MAX);
4601 tx_intf.num_props++;
4602 }
4603
4604 tx_intf.prop = tx_prop;
4605 rx_intf.prop = rx_prop;
4606
4607 /* Call the ipa api to register interface */
4608 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
4609
4610register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304611 qdf_mem_free(tx_prop);
4612 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 return ret;
4614}
4615
4616/**
4617 * hdd_remove_ipa_header() - Remove a specific header from IPA
4618 * @name: Name of the header to be removed
4619 *
4620 * Return: None
4621 */
4622static void hdd_ipa_remove_header(char *name)
4623{
4624 struct ipa_ioc_get_hdr hdrlookup;
4625 int ret = 0, len;
4626 struct ipa_ioc_del_hdr *ipa_hdr;
4627
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304628 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004629 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
4630 ret = ipa_get_hdr(&hdrlookup);
4631 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004632 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004633 name, ret);
4634 return;
4635 }
4636
Srinivas Girigowda97852372017-03-06 16:52:59 -08004637 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304639 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304641 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004642 return;
4643 }
4644 ipa_hdr->num_hdls = 1;
4645 ipa_hdr->commit = 0;
4646 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
4647 ipa_hdr->hdl[0].status = -1;
4648 ret = ipa_del_hdr(ipa_hdr);
4649 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304650 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004651 ret);
4652
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304653 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004654}
4655
4656/**
Yun Parkb187d542016-11-14 18:10:04 -08004657 * wlan_ipa_add_hdr() - Add IPA Tx header
4658 * @ipa_hdr: pointer to IPA header addition parameters
4659 *
4660 * Call IPA API to add IPA Tx header descriptor
4661 * and dump Tx header struct
4662 *
4663 * Return: 0 for success, non-zero for failure
4664 */
4665static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
4666{
4667 int ret;
4668
Srinivas Girigowda97852372017-03-06 16:52:59 -08004669 hdd_debug("==== IPA Tx Header ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08004670 "name: %s\n"
4671 "hdr_len: %d\n"
4672 "type: %d\n"
4673 "is_partial: %d\n"
4674 "hdr_hdl: 0x%x\n"
4675 "status: %d\n"
4676 "is_eth2_ofst_valid: %d\n"
4677 "eth2_ofst: %d\n",
4678 ipa_hdr->hdr[0].name,
4679 ipa_hdr->hdr[0].hdr_len,
4680 ipa_hdr->hdr[0].type,
4681 ipa_hdr->hdr[0].is_partial,
4682 ipa_hdr->hdr[0].hdr_hdl,
4683 ipa_hdr->hdr[0].status,
4684 ipa_hdr->hdr[0].is_eth2_ofst_valid,
4685 ipa_hdr->hdr[0].eth2_ofst);
4686
4687 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:",
4688 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4689
4690 ret = ipa_add_hdr(ipa_hdr);
4691 return ret;
4692}
4693
4694/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004695 * hdd_ipa_add_header_info() - Add IPA header for a given interface
4696 * @hdd_ipa: Global HDD IPA context
4697 * @iface_context: Interface-specific HDD IPA context
4698 * @mac_addr: Interface MAC address
4699 *
4700 * Return: 0 on success, negativer errno value on error
4701 */
4702static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
4703 struct hdd_ipa_iface_context *iface_context,
4704 uint8_t *mac_addr)
4705{
4706 hdd_adapter_t *adapter = iface_context->adapter;
4707 char *ifname;
4708 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
4709 int ret = -EINVAL;
4710 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
4711 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
4712
4713 ifname = adapter->dev->name;
4714
Srinivas Girigowda97852372017-03-06 16:52:59 -08004715 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004716 ifname, mac_addr);
4717
4718 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304719 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004720 + sizeof(struct ipa_hdr_add));
4721 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304722 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004723 "%s: ipa_hdr allocation failed", ifname);
4724 ret = -ENOMEM;
4725 goto end;
4726 }
4727
4728 ipa_hdr->commit = 0;
4729 ipa_hdr->num_hdrs = 1;
4730
4731 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4732 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4733 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4734 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4735 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304736 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004737 "ifname=%s, vdev_id=%d",
4738 ifname, uc_tx_hdr->ipa_hd.vdev_id);
4739 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4740 ifname, HDD_IPA_IPV4_NAME_EXT);
4741 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
4742 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
4743 ipa_hdr->hdr[0].is_partial = 1;
4744 ipa_hdr->hdr[0].hdr_hdl = 0;
4745 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4746 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4747
Yun Parkb187d542016-11-14 18:10:04 -08004748 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004749 } else {
4750 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4751
4752 /* Set the Source MAC */
4753 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
4754 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4755
4756 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4757 ifname, HDD_IPA_IPV4_NAME_EXT);
4758 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4759 ipa_hdr->hdr[0].is_partial = 1;
4760 ipa_hdr->hdr[0].hdr_hdl = 0;
4761 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4762 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4763
4764 /* Set the type to IPV4 in the header */
4765 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
4766
4767 ret = ipa_add_hdr(ipa_hdr);
4768 }
4769 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304770 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004771 ifname, ret);
4772 goto end;
4773 }
4774
Srinivas Girigowda97852372017-03-06 16:52:59 -08004775 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004776 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4777
4778 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4779 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4780 ifname, HDD_IPA_IPV6_NAME_EXT);
4781
4782 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4783 uc_tx_hdr =
4784 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4785 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004786 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004787 } else {
4788 /* Set the type to IPV6 in the header */
4789 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4790 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004791 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004792 }
4793
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004794 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304795 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004796 "%s: IPv6 add hdr failed: %d", ifname, ret);
4797 goto clean_ipv4_hdr;
4798 }
4799
Srinivas Girigowda97852372017-03-06 16:52:59 -08004800 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004801 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4802 }
4803
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304804 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004805
4806 return ret;
4807
4808clean_ipv4_hdr:
4809 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4810 ifname, HDD_IPA_IPV4_NAME_EXT);
4811 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
4812end:
4813 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304814 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004815
4816 return ret;
4817}
4818
4819/**
4820 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
4821 * @adapter: Adapter upon which IPA was previously configured
4822 *
4823 * Return: None
4824 */
4825static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
4826{
4827 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4828 int ret;
4829 char name_ipa[IPA_RESOURCE_NAME_MAX];
4830
4831 /* Remove the headers */
4832 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4833 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
4834 hdd_ipa_remove_header(name_ipa);
4835
4836 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4837 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4838 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
4839 hdd_ipa_remove_header(name_ipa);
4840 }
4841 /* unregister the interface with IPA */
4842 ret = ipa_deregister_intf(adapter->dev->name);
4843 if (ret)
Srinivas Girigowda97852372017-03-06 16:52:59 -08004844 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004845 "%s: ipa_deregister_intf fail: %d",
4846 adapter->dev->name, ret);
4847}
4848
4849/**
4850 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4851 * @iface_context: interface-specific IPA context
4852 *
4853 * Return: None
4854 */
4855static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4856{
4857 if (iface_context == NULL)
4858 return;
4859
4860 hdd_ipa_clean_hdr(iface_context->adapter);
4861
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304862 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004863 iface_context->adapter->ipa_context = NULL;
4864 iface_context->adapter = NULL;
4865 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304866 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004867 iface_context->ifa_address = 0;
4868 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304869 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004870 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304871 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004872 }
4873 iface_context->hdd_ipa->num_iface--;
4874}
4875
4876/**
4877 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4878 * @hdd_ipa: HDD IPA global context
4879 * @adapter: Interface upon which IPA is being setup
4880 * @sta_id: Station ID of the API instance
4881 *
4882 * Return: 0 on success, negative errno value on error
4883 */
4884static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
4885 hdd_adapter_t *adapter, uint8_t sta_id)
4886{
4887 struct hdd_ipa_iface_context *iface_context = NULL;
4888 void *tl_context = NULL;
4889 int i, ret = 0;
4890
4891 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4892 * channel change indication. Since these indications are sent by lower
4893 * layer as SAP updates and IPA doesn't have to do anything for these
4894 * updates so ignoring!
4895 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004896 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004897 return 0;
4898
4899 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4900 if (hdd_ipa->iface_context[i].adapter == NULL) {
4901 iface_context = &(hdd_ipa->iface_context[i]);
4902 break;
4903 }
4904 }
4905
4906 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304907 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004908 "All the IPA interfaces are in use");
4909 ret = -ENOMEM;
4910 goto end;
4911 }
4912
4913 adapter->ipa_context = iface_context;
4914 iface_context->adapter = adapter;
4915 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004916 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07004917 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004918 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304919 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004920 "Not able to get TL context sta_id: %d", sta_id);
4921 ret = -EINVAL;
4922 goto end;
4923 }
4924
4925 iface_context->tl_context = tl_context;
4926
4927 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
4928 adapter->dev->dev_addr);
4929
4930 if (ret)
4931 goto end;
4932
4933 /* Configure the TX and RX pipes filter rules */
4934 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
4935 if (ret)
4936 goto cleanup_header;
4937
4938 hdd_ipa->num_iface++;
4939 return ret;
4940
4941cleanup_header:
4942
4943 hdd_ipa_clean_hdr(adapter);
4944end:
4945 if (iface_context)
4946 hdd_ipa_cleanup_iface(iface_context);
4947 return ret;
4948}
4949
Yun Parka27049a2016-10-11 12:30:49 -07004950#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004951/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004952 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004953 * @mcc_mode: 0=MCC/1=SCC
4954 *
4955 * Return: 0 on success, negative errno value on error
4956 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004957static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004958{
4959 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304960 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004961 hdd_adapter_t *pAdapter;
4962 struct ipa_msg_meta meta;
4963 struct ipa_wlan_msg *msg;
4964 int ret;
4965
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004966 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004967 return -EINVAL;
4968
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004969 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4970 return -EINVAL;
4971
4972 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004973 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004974 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304975 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004976 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08004977 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004978 pAdapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004979 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004980 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004981 hdd_deinit_tx_rx(pAdapter);
4982 }
4983 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004984 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004985 adapter_node = next;
4986 }
4987 }
4988
4989 /* Send SCC/MCC Switching event to IPA */
4990 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304991 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004992 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004993 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004994 return -ENOMEM;
4995 }
4996
4997 meta.msg_type = mcc_mode ?
4998 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Srinivas Girigowda97852372017-03-06 16:52:59 -08004999 hdd_debug("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005000
5001 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5002
5003 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005004 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005005 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305006 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005007 }
5008
5009 return ret;
5010}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005011
5012/**
5013 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5014 * @mcc_mode: 0=MCC/1=SCC
5015 *
5016 * Return: 0 on success, negative errno value on error
5017 */
5018int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
5019{
5020 int ret;
5021
5022 cds_ssr_protect(__func__);
5023 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5024 cds_ssr_unprotect(__func__);
5025
5026 return ret;
5027}
Yun Parka27049a2016-10-11 12:30:49 -07005028#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005029
5030/**
5031 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
5032 * @event: IPA WLAN event to be converted to a string
5033 *
5034 * Return: ASCII string representing the IPA WLAN event
5035 */
5036static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
5037{
5038 switch (event) {
5039 case WLAN_CLIENT_CONNECT:
5040 return "WLAN_CLIENT_CONNECT";
5041 case WLAN_CLIENT_DISCONNECT:
5042 return "WLAN_CLIENT_DISCONNECT";
5043 case WLAN_CLIENT_POWER_SAVE_MODE:
5044 return "WLAN_CLIENT_POWER_SAVE_MODE";
5045 case WLAN_CLIENT_NORMAL_MODE:
5046 return "WLAN_CLIENT_NORMAL_MODE";
5047 case SW_ROUTING_ENABLE:
5048 return "SW_ROUTING_ENABLE";
5049 case SW_ROUTING_DISABLE:
5050 return "SW_ROUTING_DISABLE";
5051 case WLAN_AP_CONNECT:
5052 return "WLAN_AP_CONNECT";
5053 case WLAN_AP_DISCONNECT:
5054 return "WLAN_AP_DISCONNECT";
5055 case WLAN_STA_CONNECT:
5056 return "WLAN_STA_CONNECT";
5057 case WLAN_STA_DISCONNECT:
5058 return "WLAN_STA_DISCONNECT";
5059 case WLAN_CLIENT_CONNECT_EX:
5060 return "WLAN_CLIENT_CONNECT_EX";
5061
5062 case IPA_WLAN_EVENT_MAX:
5063 default:
5064 return "UNKNOWN";
5065 }
5066}
5067
5068/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005069 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5070 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5071 *
5072 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
5073 */
5074static enum ipa_wlan_event
5075hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5076{
5077 enum ipa_wlan_event ipa_event;
5078
5079 switch (hdd_ipa_event_type) {
5080 case HDD_IPA_CLIENT_CONNECT:
5081 ipa_event = WLAN_CLIENT_CONNECT;
5082 break;
5083 case HDD_IPA_CLIENT_DISCONNECT:
5084 ipa_event = WLAN_CLIENT_DISCONNECT;
5085 break;
5086 case HDD_IPA_AP_CONNECT:
5087 ipa_event = WLAN_AP_CONNECT;
5088 break;
5089 case HDD_IPA_AP_DISCONNECT:
5090 ipa_event = WLAN_AP_DISCONNECT;
5091 break;
5092 case HDD_IPA_STA_CONNECT:
5093 ipa_event = WLAN_STA_CONNECT;
5094 break;
5095 case HDD_IPA_STA_DISCONNECT:
5096 ipa_event = WLAN_STA_DISCONNECT;
5097 break;
5098 case HDD_IPA_CLIENT_CONNECT_EX:
5099 ipa_event = WLAN_CLIENT_CONNECT_EX;
5100 break;
5101 case HDD_IPA_WLAN_EVENT_MAX:
5102 default:
5103 ipa_event = IPA_WLAN_EVENT_MAX;
5104 break;
5105 }
5106 return ipa_event;
5107
5108}
5109
5110/**
5111 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005112 * @adapter: adapter upon which the event was received
5113 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005114 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005115 * @mac_address: MAC address associated with the event
5116 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005117 * This function is meant to be called from within wlan_hdd_ipa.c
5118 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005119 * Return: 0 on success, negative errno value on error
5120 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07005121static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005122 enum ipa_wlan_event type, uint8_t *mac_addr)
5123{
5124 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5125 struct ipa_msg_meta meta;
5126 struct ipa_wlan_msg *msg;
5127 struct ipa_wlan_msg_ex *msg_ex = NULL;
5128 int ret;
5129
Srinivas Girigowda97852372017-03-06 16:52:59 -08005130 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005131 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5132 mac_addr, sta_id);
5133
5134 if (type >= IPA_WLAN_EVENT_MAX)
5135 return -EINVAL;
5136
5137 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5138 return -EINVAL;
5139
5140 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305141 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005142 return -EINVAL;
5143 }
5144
5145 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5146 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005147 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005148 return 0;
5149 }
5150
5151 /*
5152 * During IPA UC resource loading/unloading new events can be issued.
5153 * Store the events separately and handle them later.
5154 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005155 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5156 if (hdd_ipa->resource_loading) {
5157 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005158 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005159
Yun Park64c405e2017-01-10 22:35:51 -08005160 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5161 "IPA resource load in progress");
Yun Park7c4f31b2016-11-30 10:09:21 -08005162
Yun Park64c405e2017-01-10 22:35:51 -08005163 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005164
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005165 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
5166 if (pending_event_count >= HDD_IPA_MAX_PENDING_EVENT_COUNT) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005167 hdd_debug("Reached max pending event count");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005168 qdf_list_remove_front(&hdd_ipa->pending_event,
5169 (qdf_list_node_t **)&pending_event);
5170 } else {
5171 pending_event =
5172 (struct ipa_uc_pending_event *)qdf_mem_malloc(
5173 sizeof(struct ipa_uc_pending_event));
5174 }
5175
5176 if (!pending_event) {
Yun Park64c405e2017-01-10 22:35:51 -08005177 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park7c4f31b2016-11-30 10:09:21 -08005178 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5179 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005180 return -ENOMEM;
5181 }
5182
5183 pending_event->adapter = adapter;
5184 pending_event->sta_id = sta_id;
5185 pending_event->type = type;
5186 qdf_mem_copy(pending_event->mac_addr,
5187 mac_addr,
5188 QDF_MAC_ADDR_SIZE);
5189 qdf_list_insert_back(&hdd_ipa->pending_event,
5190 &pending_event->node);
5191
Yun Park64c405e2017-01-10 22:35:51 -08005192 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005193 return 0;
5194 } else if (hdd_ipa->resource_unloading) {
Yun Park64c405e2017-01-10 22:35:51 -08005195 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5196 "IPA resource unload in progress");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005197 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005198 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005199 }
5200
5201 hdd_ipa->stats.event[type]++;
5202
Leo Chang3bc8fed2015-11-13 10:59:47 -08005203 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005204 switch (type) {
5205 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005206 qdf_mutex_acquire(&hdd_ipa->event_lock);
5207
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005208 /* STA already connected and without disconnect, connect again
5209 * This is Roaming scenario
5210 */
5211 if (hdd_ipa->sta_connected)
5212 hdd_ipa_cleanup_iface(adapter->ipa_context);
5213
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005214 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5215 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305216 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005217 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005218 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005219
Yun Park8f289c82016-10-18 16:38:21 -07005220 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5221 (hdd_ipa->sap_num_connected_sta > 0) &&
5222 !hdd_ipa->sta_connected) {
5223 qdf_mutex_release(&hdd_ipa->event_lock);
5224 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005225 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005226 qdf_mutex_acquire(&hdd_ipa->event_lock);
5227 }
5228
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005229 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005230 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005231 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005232
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005233 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005234
5235 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005236 break;
5237
5238 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005239 qdf_mutex_acquire(&hdd_ipa->event_lock);
5240
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005241 /* For DFS channel we get two start_bss event (before and after
5242 * CAC). Also when ACS range includes both DFS and non DFS
5243 * channels, we could possibly change channel many times due to
5244 * RADAR detection and chosen channel may not be a DFS channels.
5245 * So dont return error here. Just discard the event.
5246 */
Yun Park8f289c82016-10-18 16:38:21 -07005247 if (adapter->ipa_context) {
5248 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005249 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005250 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005251
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005252 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5253 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005254 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005255 hdd_err("%s: Evt: %d, Interface setup failed",
5256 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005257 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005258 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005259
Yun Park8f289c82016-10-18 16:38:21 -07005260 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5261 qdf_mutex_release(&hdd_ipa->event_lock);
5262 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005263 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005264 qdf_mutex_acquire(&hdd_ipa->event_lock);
5265 }
5266
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005267 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005268 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005269 (adapter->ipa_context))->iface_id;
5270
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305271 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005272 break;
5273
5274 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305275 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005276
5277 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005278 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005279 hdd_err("%s: Evt: %d, STA already disconnected",
5280 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005281 return -EINVAL;
5282 }
Yun Parka37592b2016-06-11 17:10:28 -07005283
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005284 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005285
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005286 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005287 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005288 msg_ex->name);
5289 } else {
5290 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005291 if (!hdd_ipa->num_iface &&
5292 (HDD_IPA_UC_NUM_WDI_PIPE ==
5293 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005294 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005295 }
5296
Yun Park74127cf2016-09-18 11:22:41 -07005297 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5298 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005299 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005300 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005301 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005302 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005303 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5304 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005305 }
5306
Yun Park8f289c82016-10-18 16:38:21 -07005307 hdd_ipa_cleanup_iface(adapter->ipa_context);
5308
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305309 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005310 break;
5311
5312 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005313 qdf_mutex_acquire(&hdd_ipa->event_lock);
5314
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005315 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005316 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005317 hdd_err("%s: Evt: %d, SAP already disconnected",
5318 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005319 return -EINVAL;
5320 }
5321
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005322 if ((!hdd_ipa->num_iface) &&
5323 (HDD_IPA_UC_NUM_WDI_PIPE ==
5324 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005325 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005326 /*
5327 * We disable WDI pipes directly here since
5328 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5329 * processed when unloading WLAN driver is in
5330 * progress
5331 */
5332 hdd_ipa_uc_disable_pipes(hdd_ipa);
5333 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305334 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005335 "NO INTF left but still pipe clean up");
5336 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5337 }
5338 }
5339
5340 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005341 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005342 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005343 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005344 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005345 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5346 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005347 }
Yun Parka37592b2016-06-11 17:10:28 -07005348
Yun Park8f289c82016-10-18 16:38:21 -07005349 hdd_ipa_cleanup_iface(adapter->ipa_context);
5350
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305351 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005352 break;
5353
5354 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005355 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005356 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005357 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305358 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005359 return 0;
5360 }
5361
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305362 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005363 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5364 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005365 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305366 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005367 "%s: STA ID %d found, not valid",
5368 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005369 return 0;
5370 }
Yun Park312f71a2015-12-08 10:22:42 -08005371
5372 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005373 if (hdd_ipa->sap_num_connected_sta == 0 &&
5374 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005375 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005376 hdd_ipa->sta_connected) {
5377 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005378 hdd_ipa_uc_offload_enable_disable(
5379 hdd_get_adapter(hdd_ipa->hdd_ctx,
5380 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005381 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005382 qdf_mutex_acquire(&hdd_ipa->event_lock);
5383 }
Yun Parka37592b2016-06-11 17:10:28 -07005384
Yun Park312f71a2015-12-08 10:22:42 -08005385 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5386 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305387 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005388 "%s: handle 1st con ret %d",
5389 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005390
5391 if (hdd_ipa_uc_sta_is_enabled(
5392 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005393 hdd_ipa->sta_connected) {
5394 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005395 hdd_ipa_uc_offload_enable_disable(
5396 hdd_get_adapter(
5397 hdd_ipa->hdd_ctx,
5398 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005399 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005400 } else {
5401 qdf_mutex_release(&hdd_ipa->event_lock);
5402 }
Yun Parka37592b2016-06-11 17:10:28 -07005403
Yun Park312f71a2015-12-08 10:22:42 -08005404 return ret;
5405 }
5406 }
5407
5408 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005409
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305410 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005411
5412 meta.msg_type = type;
5413 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5414 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305415 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005416
5417 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305418 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005419 "msg_ex allocation failed");
5420 return -ENOMEM;
5421 }
5422 strlcpy(msg_ex->name, adapter->dev->name,
5423 IPA_RESOURCE_NAME_MAX);
5424 msg_ex->num_of_attribs = 1;
5425 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5426 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5427 msg_ex->attribs[0].offset =
5428 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5429 } else {
5430 msg_ex->attribs[0].offset =
5431 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5432 }
5433 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5434 IPA_MAC_ADDR_SIZE);
5435
5436 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5437
5438 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005439 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305440 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305441 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005442 return ret;
5443 }
5444 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005445 return ret;
5446
5447 case WLAN_CLIENT_DISCONNECT:
5448 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005449 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005450 "%s: IPA UC OFFLOAD NOT ENABLED",
5451 msg_ex->name);
5452 return 0;
5453 }
5454
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305455 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005456 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005457 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305458 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005459 "%s: STA ID %d NOT found, not valid",
5460 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005461 return 0;
5462 }
5463 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005464
Yun Park9b5030f2016-11-08 12:02:37 -08005465 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005466 if (!hdd_ipa->sap_num_connected_sta &&
5467 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005468 if ((false == hdd_ipa->resource_unloading)
5469 && (HDD_IPA_UC_NUM_WDI_PIPE ==
5470 hdd_ipa->activated_fw_pipe)) {
5471 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5472 }
5473
Yun Park8f289c82016-10-18 16:38:21 -07005474 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005475
5476 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5477 hdd_ipa->sta_connected)
5478 hdd_ipa_uc_offload_enable_disable(
5479 hdd_get_adapter(hdd_ipa->hdd_ctx,
5480 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005481 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005482 } else {
5483 qdf_mutex_release(&hdd_ipa->event_lock);
5484 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005485 break;
5486
5487 default:
5488 return 0;
5489 }
5490
5491 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305492 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005493 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305494 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005495 return -ENOMEM;
5496 }
5497
5498 meta.msg_type = type;
5499 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5500 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5501
Srinivas Girigowda97852372017-03-06 16:52:59 -08005502 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005503 msg->name, meta.msg_type);
5504
5505 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5506
5507 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005508 hdd_err("%s: Evt: %d fail:%d",
5509 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305510 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005511 return ret;
5512 }
5513
5514 hdd_ipa->stats.num_send_msg++;
5515
5516end:
5517 return ret;
5518}
5519
5520/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005521 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005522 * @adapter: adapter upon which the event was received
5523 * @sta_id: station id for the event
5524 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5525 * @mac_address: MAC address associated with the event
5526 *
5527 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5528 *
5529 * Return: 0 on success, negative errno value on error
5530 */
5531int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
5532 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5533{
5534 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005535 int ret = 0;
5536
5537 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005538
Leo Changa202b522016-10-14 16:13:50 -07005539 /* Data path offload only support for STA and SAP mode */
5540 if ((QDF_STA_MODE == adapter->device_mode) ||
5541 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005542 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005543
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005544 cds_ssr_unprotect(__func__);
5545
5546 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005547}
5548
5549/**
5550 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5551 * @hdd_ipa: Global HDD IPA context
5552 *
5553 * Return: None
5554 */
5555static void
5556hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5557{
5558 unsigned int pending_event_count;
5559 struct ipa_uc_pending_event *pending_event = NULL;
5560
5561 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005562 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005563 "%s, Pending Event Count %d", __func__, pending_event_count);
5564 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005565 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005566 "%s, No Pending Event", __func__);
5567 return;
5568 }
5569
5570 qdf_list_remove_front(&hdd_ipa->pending_event,
5571 (qdf_list_node_t **)&pending_event);
5572 while (pending_event != NULL) {
5573 __hdd_ipa_wlan_evt(pending_event->adapter,
5574 pending_event->type,
5575 pending_event->sta_id,
5576 pending_event->mac_addr);
5577 qdf_mem_free(pending_event);
5578 pending_event = NULL;
5579 qdf_list_remove_front(&hdd_ipa->pending_event,
5580 (qdf_list_node_t **)&pending_event);
5581 }
5582}
5583
5584/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005585 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5586 * @state: IPA RM state value
5587 *
5588 * Return: ASCII string representing the IPA RM state
5589 */
5590static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5591{
5592 switch (state) {
5593 case HDD_IPA_RM_RELEASED:
5594 return "RELEASED";
5595 case HDD_IPA_RM_GRANT_PENDING:
5596 return "GRANT_PENDING";
5597 case HDD_IPA_RM_GRANTED:
5598 return "GRANTED";
5599 }
5600
5601 return "UNKNOWN";
5602}
5603
5604/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005605 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005606 * @hdd_ctx: HDD global context
5607 *
5608 * Allocate hdd_ipa resources, ipa pipe resource and register
5609 * wlan interface with IPA module.
5610 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305611 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005612 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005613static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005614{
5615 struct hdd_ipa_priv *hdd_ipa = NULL;
5616 int ret, i;
5617 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005618 struct ol_txrx_pdev_t *pdev = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005619
5620 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305621 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005622
Yun Parkbaa62862017-01-18 13:43:34 -08005623 ENTER();
5624
5625 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005626 if (!pdev) {
5627 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5628 goto fail_return;
5629 }
5630
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305631 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005632 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305633 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005634 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005635 }
5636
5637 hdd_ctx->hdd_ipa = hdd_ipa;
5638 ghdd_ipa = hdd_ipa;
5639 hdd_ipa->hdd_ctx = hdd_ctx;
5640 hdd_ipa->num_iface = 0;
5641
5642 /* Create the interface context */
5643 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5644 iface_context = &hdd_ipa->iface_context[i];
5645 iface_context->hdd_ipa = hdd_ipa;
5646 iface_context->cons_client =
5647 hdd_ipa_adapter_2_client[i].cons_client;
5648 iface_context->prod_client =
5649 hdd_ipa_adapter_2_client[i].prod_client;
5650 iface_context->iface_id = i;
5651 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305652 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005653 }
5654 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005655 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5656 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005657 }
5658
Leo Chang69c39692016-10-12 20:11:12 -07005659 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305660 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305661 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005662
5663 ret = hdd_ipa_setup_rm(hdd_ipa);
5664 if (ret)
5665 goto fail_setup_rm;
5666
5667 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5668 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305669 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005670 hdd_ipa->sap_num_connected_sta = 0;
5671 hdd_ipa->ipa_tx_packets_diff = 0;
5672 hdd_ipa->ipa_rx_packets_diff = 0;
5673 hdd_ipa->ipa_p_tx_packets = 0;
5674 hdd_ipa->ipa_p_rx_packets = 0;
5675 hdd_ipa->resource_loading = false;
5676 hdd_ipa->resource_unloading = false;
5677 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005678 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08005679 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005680 /* Setup IPA sys_pipe for MCC */
5681 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5682 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5683 if (ret)
5684 goto fail_create_sys_pipe;
5685 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005686 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5687 goto fail_create_sys_pipe;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005688 } else {
5689 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5690 if (ret)
5691 goto fail_create_sys_pipe;
5692 }
5693
Yun Parkbaa62862017-01-18 13:43:34 -08005694 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305695 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005696
5697fail_create_sys_pipe:
5698 hdd_ipa_destroy_rm_resource(hdd_ipa);
5699fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305700 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305701 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005702 hdd_ctx->hdd_ipa = NULL;
5703 ghdd_ipa = NULL;
5704fail_return:
Yun Parkbaa62862017-01-18 13:43:34 -08005705 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305706 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005707}
5708
5709/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005710 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5711 * @hdd_ctx: HDD global context
5712 *
5713 * Allocate hdd_ipa resources, ipa pipe resource and register
5714 * wlan interface with IPA module.
5715 *
5716 * Return: QDF_STATUS enumeration
5717 */
5718QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
5719{
5720 QDF_STATUS ret;
5721
5722 cds_ssr_protect(__func__);
5723 ret = __hdd_ipa_init(hdd_ctx);
5724 cds_ssr_unprotect(__func__);
5725
5726 return ret;
5727}
5728
Arun Khandavallicc544b32017-01-30 19:52:16 +05305729
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005730/**
Yun Parkf19e07d2015-11-20 11:34:27 -08005731 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
5732 * @hdd_ipa: pointer to HDD IPA struct
5733 *
5734 * Return: none
5735 */
Jeff Johnsond7720632016-10-05 16:04:32 -07005736static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08005737{
5738 struct ipa_uc_pending_event *pending_event = NULL;
5739
Anurag Chouhanffb21542016-02-17 14:33:03 +05305740 while (qdf_list_remove_front(&hdd_ipa->pending_event,
5741 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305742 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005743 }
5744
Anurag Chouhanffb21542016-02-17 14:33:03 +05305745 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005746}
5747
5748/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005749 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005750 * @hdd_ctx: HDD global context
5751 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305752 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005753 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005754static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005755{
5756 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5757 int i;
5758 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305759 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005760 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5761
5762 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305763 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005764
5765 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5766 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5767 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5768 }
5769
5770 /* Teardown IPA sys_pipe for MCC */
5771 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5772 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5773
5774 hdd_ipa_destroy_rm_resource(hdd_ipa);
5775
5776#ifdef WLAN_OPEN_SOURCE
5777 cancel_work_sync(&hdd_ipa->pm_work);
5778#endif
5779
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305780 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005781
Nirav Shahcbc6d722016-03-01 16:24:53 +05305782 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5783 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305784 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005785
5786 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
5787 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
5788
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305789 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005790 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305791 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005792
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305793 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005794
5795 /* destory the interface lock */
5796 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5797 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305798 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005799 }
5800
5801 /* This should never hit but still make sure that there are no pending
5802 * descriptor in IPA hardware
5803 */
5804 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305805 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005806 "IPA Pending write done: %d Waiting!",
5807 hdd_ipa->pending_hw_desc_cnt);
5808
5809 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
5810 usleep_range(100, 100);
5811 }
5812
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305813 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005814 "IPA Pending write done: desc: %d %s(%d)!",
5815 hdd_ipa->pending_hw_desc_cnt,
5816 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
5817 : "leak", i);
5818 }
5819 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08005820 if (ipa_uc_dereg_rdyCB())
5821 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5822 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005823 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005824 if (true == hdd_ipa->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005825 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Govind Singh0487bf22016-08-24 23:08:57 +05305826 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
5827 __func__, hdd_ipa->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005828 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005829 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Govind Singh0487bf22016-08-24 23:08:57 +05305830 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
5831 __func__, hdd_ipa->rx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005832 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
5833 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305834 qdf_mutex_destroy(&hdd_ipa->event_lock);
5835 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005836 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005837
5838#ifdef WLAN_OPEN_SOURCE
5839 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5840 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5841 hdd_ipa->uc_op_work[i].msg = NULL;
5842 }
5843#endif
5844 }
5845
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305846 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005847 hdd_ctx->hdd_ipa = NULL;
5848
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305849 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005850}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005851
5852/**
5853 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5854 * @hdd_ctx: HDD global context
5855 *
5856 * Return: QDF_STATUS enumeration
5857 */
5858QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
5859{
5860 QDF_STATUS ret;
5861
5862 cds_ssr_protect(__func__);
5863 ret = __hdd_ipa_cleanup(hdd_ctx);
5864 cds_ssr_unprotect(__func__);
5865
5866 return ret;
5867}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005868#endif /* IPA_OFFLOAD */