blob: 78d7aa808697e0bee797a86e42f398db3e17cace [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
jge62037862016-12-09 10:44:33 +08002 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ipa.c
30 *
31 * WLAN HDD and ipa interface implementation
32 * Originally written by Qualcomm Atheros, Inc
33 */
34
35#ifdef IPA_OFFLOAD
36
37/* Include Files */
Mohit Khannafa99aea2016-05-12 21:43:13 -070038#include <linux/ipa.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039#include <wlan_hdd_includes.h>
40#include <wlan_hdd_ipa.h>
41
42#include <linux/etherdevice.h>
43#include <linux/atomic.h>
44#include <linux/netdevice.h>
45#include <linux/skbuff.h>
46#include <linux/list.h>
47#include <linux/debugfs.h>
48#include <linux/inetdevice.h>
49#include <linux/ip.h>
50#include <wlan_hdd_softap_tx_rx.h>
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +053051#include <ol_txrx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070052#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053
54#include "cds_sched.h"
55
56#include "wma.h"
57#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080058#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
Dhanashri Atreb08959a2016-03-01 17:28:03 -080060#include "cdp_txrx_ipa.h"
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -080061#include <cdp_txrx_handle.h>
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -080062#include "wlan_policy_mgr_api.h"
63
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080064#define HDD_IPA_DESC_BUFFER_RATIO 4
65#define HDD_IPA_IPV4_NAME_EXT "_ipv4"
66#define HDD_IPA_IPV6_NAME_EXT "_ipv6"
67
68#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
70/* WDI TX and RX PIPE */
71#define HDD_IPA_UC_NUM_WDI_PIPE 2
72#define HDD_IPA_UC_MAX_PENDING_EVENT 33
73
74#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
75#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
76#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
77#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
78
79#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
80#define HDD_IPA_MAX_IFACE 3
81#define HDD_IPA_MAX_SYSBAM_PIPE 4
82#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
83#define HDD_IPA_ENABLE_MASK BIT(0)
84#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
85#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
86#define HDD_IPA_RM_ENABLE_MASK BIT(3)
87#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
88#define HDD_IPA_UC_ENABLE_MASK BIT(5)
89#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
90#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
91
Yun Parkf19e07d2015-11-20 11:34:27 -080092#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
93
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -070094enum hdd_ipa_uc_op_code {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080095 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
96 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
97 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
98 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
99 HDD_IPA_UC_OPCODE_STATS = 4,
Yun Park637d6482016-10-05 10:51:33 -0700100#ifdef FEATURE_METERING
101 HDD_IPA_UC_OPCODE_SHARING_STATS = 5,
102 HDD_IPA_UC_OPCODE_QUOTA_RSP = 6,
103 HDD_IPA_UC_OPCODE_QUOTA_IND = 7,
104#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800105 HDD_IPA_UC_OPCODE_UC_READY = 8,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800106 /* keep this last */
107 HDD_IPA_UC_OPCODE_MAX
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700108};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800109
110/**
111 * enum - Reason codes for stat query
112 *
113 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
114 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
115 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800116 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800117 */
118enum {
119 HDD_IPA_UC_STAT_REASON_NONE,
120 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -0800121 HDD_IPA_UC_STAT_REASON_BW_CAL,
122 HDD_IPA_UC_STAT_REASON_DUMP_INFO
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800123};
124
125/**
126 * enum hdd_ipa_rm_state - IPA resource manager state
127 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
128 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
129 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
130 */
131enum hdd_ipa_rm_state {
132 HDD_IPA_RM_RELEASED,
133 HDD_IPA_RM_GRANT_PENDING,
134 HDD_IPA_RM_GRANTED,
135};
136
137struct llc_snap_hdr {
138 uint8_t dsap;
139 uint8_t ssap;
140 uint8_t resv[4];
141 __be16 eth_type;
142} __packed;
143
Leo Chang3bc8fed2015-11-13 10:59:47 -0800144/**
145 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
146 * @eth: ether II header
147 * @llc_snap: LLC snap header
148 *
149 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800150struct hdd_ipa_tx_hdr {
151 struct ethhdr eth;
152 struct llc_snap_hdr llc_snap;
153} __packed;
154
Leo Chang3bc8fed2015-11-13 10:59:47 -0800155/**
156 * struct frag_header - fragment header type registered to IPA hardware
157 * @length: fragment length
158 * @reserved1: Reserved not used
159 * @reserved2: Reserved not used
160 *
161 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800162struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800163 uint16_t length;
164 uint32_t reserved1;
165 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800166} __packed;
167
Leo Chang3bc8fed2015-11-13 10:59:47 -0800168/**
169 * struct ipa_header - ipa header type registered to IPA hardware
170 * @vdev_id: vdev id
171 * @reserved: Reserved not used
172 *
173 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174struct ipa_header {
175 uint32_t
176 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
177 reserved:24;
178} __packed;
179
Leo Chang3bc8fed2015-11-13 10:59:47 -0800180/**
181 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
182 * @frag_hd: fragment header
183 * @ipa_hd: ipa header
184 * @eth: ether II header
185 *
186 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800187struct hdd_ipa_uc_tx_hdr {
188 struct frag_header frag_hd;
189 struct ipa_header ipa_hd;
190 struct ethhdr eth;
191} __packed;
192
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800193/**
194 * struct hdd_ipa_cld_hdr - IPA CLD Header
195 * @reserved: reserved fields
196 * @iface_id: interface ID
197 * @sta_id: Station ID
198 *
199 * Packed 32-bit structure
200 * +----------+----------+--------------+--------+
201 * | Reserved | QCMAP ID | interface id | STA ID |
202 * +----------+----------+--------------+--------+
203 */
204struct hdd_ipa_cld_hdr {
205 uint8_t reserved[2];
206 uint8_t iface_id;
207 uint8_t sta_id;
208} __packed;
209
210struct hdd_ipa_rx_hdr {
211 struct hdd_ipa_cld_hdr cld_hdr;
212 struct ethhdr eth;
213} __packed;
214
215struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700216 bool exception;
217 hdd_adapter_t *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800218 struct hdd_ipa_iface_context *iface_context;
219 struct ipa_rx_data *ipa_tx_desc;
220};
221
222struct hdd_ipa_uc_rx_hdr {
223 struct ethhdr eth;
224} __packed;
225
226struct hdd_ipa_sys_pipe {
227 uint32_t conn_hdl;
228 uint8_t conn_hdl_valid;
229 struct ipa_sys_connect_params ipa_sys_params;
230};
231
232struct hdd_ipa_iface_stats {
233 uint64_t num_tx;
234 uint64_t num_tx_drop;
235 uint64_t num_tx_err;
236 uint64_t num_tx_cac_drop;
237 uint64_t num_rx_prefilter;
238 uint64_t num_rx_ipa_excep;
239 uint64_t num_rx_recv;
240 uint64_t num_rx_recv_mul;
241 uint64_t num_rx_send_desc_err;
242 uint64_t max_rx_mul;
243};
244
245struct hdd_ipa_priv;
246
247struct hdd_ipa_iface_context {
248 struct hdd_ipa_priv *hdd_ipa;
249 hdd_adapter_t *adapter;
250 void *tl_context;
251
252 enum ipa_client_type cons_client;
253 enum ipa_client_type prod_client;
254
255 uint8_t iface_id; /* This iface ID */
256 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530257 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800258 uint32_t ifa_address;
259 struct hdd_ipa_iface_stats stats;
260};
261
262struct hdd_ipa_stats {
263 uint32_t event[IPA_WLAN_EVENT_MAX];
264 uint64_t num_send_msg;
265 uint64_t num_free_msg;
266
267 uint64_t num_rm_grant;
268 uint64_t num_rm_release;
269 uint64_t num_rm_grant_imm;
270 uint64_t num_cons_perf_req;
271 uint64_t num_prod_perf_req;
272
273 uint64_t num_rx_drop;
274 uint64_t num_rx_ipa_tx_dp;
275 uint64_t num_rx_ipa_splice;
276 uint64_t num_rx_ipa_loop;
277 uint64_t num_rx_ipa_tx_dp_err;
278 uint64_t num_rx_ipa_write_done;
279 uint64_t num_max_ipa_tx_mul;
280 uint64_t num_rx_ipa_hw_maxed_out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800281
Yun Park52b2b992016-09-22 15:49:51 -0700282 uint64_t num_tx_desc_q_cnt;
283 uint64_t num_tx_desc_error;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800284 uint64_t num_tx_comp_cnt;
285 uint64_t num_tx_queued;
286 uint64_t num_tx_dequeued;
287 uint64_t num_max_pm_queue;
288
289 uint64_t num_freeq_empty;
290 uint64_t num_pri_freeq_empty;
291 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800292 uint64_t num_tx_fwd_ok;
293 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800294};
295
296struct ipa_uc_stas_map {
297 bool is_reserved;
298 uint8_t sta_id;
299};
300struct op_msg_type {
301 uint8_t msg_t;
302 uint8_t rsvd;
303 uint16_t op_code;
304 uint16_t len;
305 uint16_t rsvd_snd;
306};
307
308struct ipa_uc_fw_stats {
309 uint32_t tx_comp_ring_base;
310 uint32_t tx_comp_ring_size;
311 uint32_t tx_comp_ring_dbell_addr;
312 uint32_t tx_comp_ring_dbell_ind_val;
313 uint32_t tx_comp_ring_dbell_cached_val;
314 uint32_t tx_pkts_enqueued;
315 uint32_t tx_pkts_completed;
316 uint32_t tx_is_suspend;
317 uint32_t tx_reserved;
318 uint32_t rx_ind_ring_base;
319 uint32_t rx_ind_ring_size;
320 uint32_t rx_ind_ring_dbell_addr;
321 uint32_t rx_ind_ring_dbell_ind_val;
322 uint32_t rx_ind_ring_dbell_ind_cached_val;
323 uint32_t rx_ind_ring_rdidx_addr;
324 uint32_t rx_ind_ring_rd_idx_cached_val;
325 uint32_t rx_refill_idx;
326 uint32_t rx_num_pkts_indicated;
327 uint32_t rx_buf_refilled;
328 uint32_t rx_num_ind_drop_no_space;
329 uint32_t rx_num_ind_drop_no_buf;
330 uint32_t rx_is_suspend;
331 uint32_t rx_reserved;
332};
333
334struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530335 qdf_list_node_t node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800336 hdd_adapter_t *adapter;
337 enum ipa_wlan_event type;
338 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530339 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800340};
341
342/**
343 * struct uc_rm_work_struct
344 * @work: uC RM work
345 * @event: IPA RM event
346 */
347struct uc_rm_work_struct {
348 struct work_struct work;
349 enum ipa_rm_event event;
350};
351
352/**
353 * struct uc_op_work_struct
354 * @work: uC OP work
355 * @msg: OP message
356 */
357struct uc_op_work_struct {
358 struct work_struct work;
359 struct op_msg_type *msg;
360};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800361
362/**
363 * struct uc_rt_debug_info
364 * @time: system time
365 * @ipa_excep_count: IPA exception packet count
366 * @rx_drop_count: IPA Rx drop packet count
367 * @net_sent_count: IPA Rx packet sent to network stack count
368 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800369 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370 * @tx_fwd_count: IPA Tx forward packet count
371 * @rx_destructor_call: IPA Rx packet destructor count
372 */
373struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530374 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800375 uint64_t ipa_excep_count;
376 uint64_t rx_drop_count;
377 uint64_t net_sent_count;
378 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800379 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800380 uint64_t tx_fwd_count;
381 uint64_t rx_destructor_call;
382};
383
Yun Park637d6482016-10-05 10:51:33 -0700384#ifdef FEATURE_METERING
385struct ipa_uc_sharing_stats {
386 uint64_t ipv4_rx_packets;
387 uint64_t ipv4_rx_bytes;
388 uint64_t ipv6_rx_packets;
389 uint64_t ipv6_rx_bytes;
390 uint64_t ipv4_tx_packets;
391 uint64_t ipv4_tx_bytes;
392 uint64_t ipv6_tx_packets;
393 uint64_t ipv6_tx_bytes;
394};
395
396struct ipa_uc_quota_rsp {
397 uint8_t success;
398 uint8_t reserved[3];
399 uint32_t quota_lo; /* quota limit low bytes */
400 uint32_t quota_hi; /* quota limit high bytes */
401};
402
403struct ipa_uc_quota_ind {
404 uint64_t quota_bytes; /* quota limit in bytes */
405};
406#endif
407
Yun Park52b2b992016-09-22 15:49:51 -0700408/**
409 * struct hdd_ipa_tx_desc
410 * @link: link to list head
411 * @priv: pointer to priv list entry
412 * @id: Tx desc idex
413 * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor
414 */
415struct hdd_ipa_tx_desc {
416 struct list_head link;
417 void *priv;
418 uint32_t id;
419 struct ipa_rx_data *ipa_tx_desc_ptr;
420};
421
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800422struct hdd_ipa_priv {
423 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
424 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
425 uint8_t num_iface;
426 enum hdd_ipa_rm_state rm_state;
427 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530428 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800429 * APIs as it is taken care gracefully. Without this, kernel would throw
430 * an warning if spin_lock_bh is used while IRQ is disabled
431 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530432 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800433 struct uc_rm_work_struct uc_rm_work;
434 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530435 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800436 struct delayed_work wake_lock_work;
437 bool wake_lock_released;
438
439 enum ipa_client_type prod_client;
440
441 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530442 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800443 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530444 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800445 bool suspended;
446
Yun Park52b2b992016-09-22 15:49:51 -0700447 qdf_spinlock_t q_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800448
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800449 struct list_head pend_desc_head;
Yun Park52b2b992016-09-22 15:49:51 -0700450 struct hdd_ipa_tx_desc *tx_desc_list;
451 struct list_head free_tx_desc_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800452
453 hdd_context_t *hdd_ctx;
454
455 struct dentry *debugfs_dir;
456 struct hdd_ipa_stats stats;
457
458 struct notifier_block ipv4_notifier;
459 uint32_t curr_prod_bw;
460 uint32_t curr_cons_bw;
461
462 uint8_t activated_fw_pipe;
463 uint8_t sap_num_connected_sta;
464 uint8_t sta_connected;
465 uint32_t tx_pipe_handle;
466 uint32_t rx_pipe_handle;
467 bool resource_loading;
468 bool resource_unloading;
469 bool pending_cons_req;
470 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530471 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530472 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700473 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474 uint32_t ipa_tx_packets_diff;
475 uint32_t ipa_rx_packets_diff;
476 uint32_t ipa_p_tx_packets;
477 uint32_t ipa_p_rx_packets;
478 uint32_t stat_req_reason;
479 uint64_t ipa_tx_forward;
480 uint64_t ipa_rx_discard;
481 uint64_t ipa_rx_net_send_count;
482 uint64_t ipa_rx_internel_drop_count;
483 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530484 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800485 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
486 unsigned int rt_buf_fill_index;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800487 struct ipa_wdi_in_params cons_pipe_in;
488 struct ipa_wdi_in_params prod_pipe_in;
489 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800490 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530491 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530492 qdf_mutex_t rt_debug_lock;
493 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800494 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800495 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530496 qdf_dma_addr_t tx_comp_doorbell_paddr;
497 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800498 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
499 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Yun Park637d6482016-10-05 10:51:33 -0700500#ifdef FEATURE_METERING
501 struct ipa_uc_sharing_stats ipa_sharing_stats;
502 struct ipa_uc_quota_rsp ipa_quota_rsp;
503 struct ipa_uc_quota_ind ipa_quota_ind;
504 struct completion ipa_uc_sharing_stats_comp;
505 struct completion ipa_uc_set_quota_comp;
506#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507};
508
Leo Changcc923e22016-06-16 15:29:03 -0700509#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
510#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800511#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
512#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
513#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
514#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
515#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
516#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700517#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
518 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800519
520#define HDD_IPA_GET_IFACE_ID(_data) \
521 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
522
523#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530524 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525 "%s:%d: "fmt, __func__, __LINE__, ## args)
526
Govind Singhb6a89772016-08-12 11:23:35 +0530527#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
528 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
529 "%s:%d: "fmt, __func__, __LINE__, ## args)
530
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800531#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
532 do { \
Yun Parkec845302016-12-15 09:22:57 -0800533 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \
534 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800535 } while (0)
536
537#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
538 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
539
540#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
541 do { \
542 hdd_ipa->ipa_rx_internel_drop_count++; \
543 } while (0)
544#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
545 do { \
546 hdd_ipa->ipa_rx_net_send_count++; \
547 } while (0)
548#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
549
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700550#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800551#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
552do { \
553 pipe_in.u.ul.rdy_ring_rp_va = \
554 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
555 pipe_in.u.ul.rdy_comp_ring_base_pa = \
556 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
557 pipe_in.u.ul.rdy_comp_ring_size = \
558 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
559 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
560 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
561 pipe_in.u.ul.rdy_comp_ring_wp_va = \
562 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800563} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700564
565#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800566#else
567/* Do nothing */
568#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
Leo Chang63d73612016-10-18 18:09:43 -0700569#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700570#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800571
Yun Parkb187d542016-11-14 18:10:04 -0800572#define HDD_IPA_DBG_DUMP_RX_LEN 32
573#define HDD_IPA_DBG_DUMP_TX_LEN 48
574
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800575static struct hdd_ipa_adapter_2_client {
576 enum ipa_client_type cons_client;
577 enum ipa_client_type prod_client;
578} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
579 {
580 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
581 }, {
582 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
583 }, {
584 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
585 },
586};
587
588/* For Tx pipes, use Ethernet-II Header format */
589struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
590 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800591 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800592 0x00000000,
593 0x00000000
594 },
595 {
596 0x00000000
597 },
598 {
599 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
600 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
601 0x0008
602 }
603};
604
605/* For Tx pipes, use 802.3 Header format */
606static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
607 {
608 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
609 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
610 0x00 /* length can be zero */
611 },
612 {
613 /* LLC SNAP header 8 bytes */
614 0xaa, 0xaa,
615 {0x03, 0x00, 0x00, 0x00},
616 0x0008 /* type value(2 bytes) ,filled by wlan */
617 /* 0x0800 - IPV4, 0x86dd - IPV6 */
618 }
619};
620
Yun Park637d6482016-10-05 10:51:33 -0700621#ifdef FEATURE_METERING
622#define IPA_UC_SHARING_STATES_WAIT_TIME 500
623#define IPA_UC_SET_QUOTA_WAIT_TIME 500
624#endif
625
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800626static struct hdd_ipa_priv *ghdd_ipa;
627
628/* Local Function Prototypes */
629static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
630 unsigned long data);
631static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
632 unsigned long data);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800633static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800634
635static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700636static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800637
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800638#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
639 defined(IPA_CLIENT_IS_MHI_CONS))
640/**
641 * hdd_ipa_uc_get_db_paddr() - Get Doorbell physical address
642 * @db_paddr: Doorbell physical address should be given bu IPA
643 * @client: IPA client type
644 *
645 * Query doorbell physical address from IPA
646 * IPA will give physical address for TX COMP and RX READY
647 *
648 * Return: None
649 */
650static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
651 enum ipa_client_type client)
652{
653 struct ipa_wdi_db_params dbpa;
654
655 dbpa.client = client;
656 ipa_uc_wdi_get_dbpa(&dbpa);
657 *db_paddr = dbpa.uc_door_bell_pa;
Srinivas Girigowda97852372017-03-06 16:52:59 -0800658 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s PROD DB get dbpa 0x%x",
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800659 __func__, (unsigned int)dbpa.uc_door_bell_pa);
660}
661
662/**
663 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
664 * @priv_ctxt: hdd ipa local context
665 *
666 * Will be called by IPA context.
667 * It's atomic context, then should be scheduled to kworker thread
668 *
669 * Return: None
670 */
671static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
672{
673 struct hdd_ipa_priv *hdd_ipa;
674 struct op_msg_type *msg;
675 struct uc_op_work_struct *uc_op_work;
676
677 if (priv_ctxt == NULL) {
678 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
679 return;
680 }
681
682 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
683 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
684 if (!msg) {
685 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
686 return;
687 }
688
689 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
690
691 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
692
693 /* When the same uC OPCODE is already pended, just return */
694 if (uc_op_work->msg)
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530695 goto done;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800696
697 uc_op_work->msg = msg;
698 schedule_work(&uc_op_work->work);
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530699
700done:
701 qdf_mem_free(msg);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800702}
703
704/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800705 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
706 * @ctrl: WDI control value
707 *
708 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
709 *
710 * Return: 0 on message send to ipa, -1 on failure
711 */
712static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
713{
714 struct ipa_msg_meta meta;
715 struct ipa_wlan_msg *ipa_msg;
716 int ret = 0;
717
718 /* WDI enable message to IPA */
719 meta.msg_len = sizeof(*ipa_msg);
720 ipa_msg = qdf_mem_malloc(meta.msg_len);
721 if (ipa_msg == NULL) {
722 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
723 "msg allocation failed");
724 return -ENOMEM;
725 }
726
727 if (ctrl == true)
728 meta.msg_type = WLAN_WDI_ENABLE;
729 else
730 meta.msg_type = WLAN_WDI_DISABLE;
731
Srinivas Girigowda97852372017-03-06 16:52:59 -0800732 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800733 "ipa_send_msg(Evt:%d)", meta.msg_type);
734 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
735 if (ret) {
736 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
737 "ipa_send_msg(Evt:%d)-fail=%d",
738 meta.msg_type, ret);
739 qdf_mem_free(ipa_msg);
740 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800741 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800742}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800743
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800744/**
745 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
746 * @hdd_ipa: HDD IPA local context
747 *
748 * Register IPA UC ready callback function to IPA kernel driver
749 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
750 * open WDI pipe after WLAN driver loading finished
751 *
752 * Return: 0 Success
753 * -EPERM Registration fail
754 */
755static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
756{
757 struct ipa_wdi_uc_ready_params uc_ready_param;
758 int ret = 0;
759
760 hdd_ipa->uc_loaded = false;
761 uc_ready_param.priv = (void *)hdd_ipa;
762 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
763 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
764 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
765 "UC Ready CB register fail");
766 return -EPERM;
767 }
768 if (true == uc_ready_param.is_uC_ready) {
Srinivas Girigowda2b5d47c2017-03-29 00:28:46 -0700769 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800770 hdd_ipa->uc_loaded = true;
771 } else {
772 ret = hdd_ipa_uc_send_wdi_control_msg(false);
773 }
774
775 return ret;
776}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800777#else
778static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
779 enum ipa_client_type client)
780{
781 /* Do nothing */
782}
783
784static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
785{
786 hdd_ipa->uc_loaded = true;
787 return 0;
788}
789
790static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
791{
792 return 0;
793}
794#endif
795
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796/**
797 * hdd_ipa_is_enabled() - Is IPA enabled?
798 * @hdd_ctx: Global HDD context
799 *
800 * Return: true if IPA is enabled, false otherwise
801 */
802bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
803{
804 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
805}
806
807/**
808 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
809 * @hdd_ctx: Global HDD context
810 *
811 * Return: true if IPA uC offload is enabled, false otherwise
812 */
813bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
814{
815 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
816}
817
818/**
819 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
820 * @hdd_ctx: Global HDD context
821 *
822 * Return: true if STA mode IPA uC offload is enabled, false otherwise
823 */
824static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
825{
826 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
827}
828
829/**
Guolei Bianca144d82016-11-10 11:07:42 +0800830 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
831 * @hdd_ipa: Global HDD IPA context
832 *
833 * Return: None
834 */
Guolei Bianca144d82016-11-10 11:07:42 +0800835static inline void hdd_ipa_uc_sta_reset_sta_connected(
836 struct hdd_ipa_priv *hdd_ipa)
837{
Yun Park637d6482016-10-05 10:51:33 -0700838 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800839 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700840 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800841}
Guolei Bianca144d82016-11-10 11:07:42 +0800842
843/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800844 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
845 * @hdd_ipa: Global HDD IPA context
846 *
847 * Return: true if pre-filter is enabled, otherwise false
848 */
849static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
850{
851 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
852 HDD_IPA_PRE_FILTER_ENABLE_MASK);
853}
854
855/**
856 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
857 * @hdd_ipa: Global HDD IPA context
858 *
859 * Return: true if IPv6 is enabled, otherwise false
860 */
861static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
862{
863 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
864}
865
866/**
867 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
868 * @hdd_ipa: Global HDD IPA context
869 *
870 * Return: true if resource manager is enabled, otherwise false
871 */
872static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
873{
874 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
875}
876
877/**
878 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
879 * @hdd_ipa: Global HDD IPA context
880 *
881 * Return: true if resource manager is enabled, otherwise false
882 */
883static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
884{
885 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
886}
887
888/**
889 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
890 * @hdd_ipa: Global HDD IPA context
891 *
892 * Return: true if clock scaling is enabled, otherwise false
893 */
894static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
895{
896 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
897 HDD_IPA_CLK_SCALING_ENABLE_MASK |
898 HDD_IPA_RM_ENABLE_MASK);
899}
900
901/**
902 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
903 * @ctext: pointer to hdd context.
904 *
905 * If rt debug enabled, periodically called, and fill debug buffer
906 *
907 * Return: none
908 */
909static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
910{
911 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
912 struct hdd_ipa_priv *hdd_ipa;
913 struct uc_rt_debug_info *dump_info = NULL;
914
915 if (wlan_hdd_validate_context(hdd_ctx))
916 return;
917
918 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800919 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800920 "%s: IPA UC is not enabled", __func__);
921 return;
922 }
923
924 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
925
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530926 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800927 dump_info = &hdd_ipa->rt_bug_buffer[
928 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
929
Deepthi Gowri6acee342016-10-28 15:00:38 +0530930 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
932 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
933 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800935 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
936 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800937 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
938 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530939 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800940
Anurag Chouhan210db072016-02-22 18:42:15 +0530941 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800942 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
943}
944
945/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700946 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800947 * @hdd_ctx: pointer to hdd context.
948 *
949 * If rt debug enabled, dump debug buffer contents based on requirement
950 *
951 * Return: none
952 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700953static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800954{
955 struct hdd_ipa_priv *hdd_ipa;
956 unsigned int dump_count;
957 unsigned int dump_index;
958 struct uc_rt_debug_info *dump_info = NULL;
959
960 if (wlan_hdd_validate_context(hdd_ctx))
961 return;
962
963 hdd_ipa = hdd_ctx->hdd_ipa;
964 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800965 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800966 "%s: IPA UC is not enabled", __func__);
967 return;
968 }
969
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530970 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800971 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530972 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800973 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800974
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530975 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800976 for (dump_count = 0;
977 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
978 dump_count++) {
979 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
980 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
981 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530982 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530983 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800984 dump_info->time, dump_info->ipa_excep_count,
985 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800986 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800987 dump_info->rx_destructor_call,
988 dump_info->rx_discard_count);
989 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530990 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530991 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800992 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
993}
994
995/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700996 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
997 * __hdd_ipa_uc_rt_debug_host_dump
998 * @hdd_ctx: pointer to hdd context.
999 *
1000 * If rt debug enabled, dump debug buffer contents based on requirement
1001 *
1002 * Return: none
1003 */
1004void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
1005{
1006 cds_ssr_protect(__func__);
1007 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1008 cds_ssr_unprotect(__func__);
1009}
1010
1011/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001012 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
1013 * @ctext: pointer to hdd context.
1014 *
1015 * periodically called by timer expire
1016 * will try to alloc dummy memory and detect out of memory condition
1017 * if out of memory detected, dump wlan-ipa stats
1018 *
1019 * Return: none
1020 */
1021static void hdd_ipa_uc_rt_debug_handler(void *ctext)
1022{
1023 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001024 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001025 void *dummy_ptr = NULL;
1026
1027 if (wlan_hdd_validate_context(hdd_ctx))
1028 return;
1029
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001030 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1031
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001033 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034 return;
1035 }
1036
1037 /* Allocate dummy buffer periodically and free immediately. this will
1038 * proactively detect OOM and if allocation fails dump ipa stats
1039 */
1040 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
1041 GFP_KERNEL | GFP_ATOMIC);
1042 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1044 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -07001045 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
1046 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001047 } else {
1048 kfree(dummy_ptr);
1049 }
1050
Anurag Chouhan210db072016-02-22 18:42:15 +05301051 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052 HDD_IPA_UC_RT_DEBUG_PERIOD);
1053}
1054
1055/**
Yun Parkb187d542016-11-14 18:10:04 -08001056 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057 * @skb: packet pinter
1058 *
1059 * when free data packet, will be invoked by wlan client and will increase
1060 * free counter
1061 *
1062 * Return: none
1063 */
Jeff Johnsond7720632016-10-05 16:04:32 -07001064static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065{
1066 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301067 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001068 "%s: invalid hdd context", __func__);
1069 return;
1070 }
1071
1072 ghdd_ipa->ipa_rx_destructor_count++;
1073}
1074
1075/**
Yun Parkb187d542016-11-14 18:10:04 -08001076 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001077 * @hdd_ctx: hdd main context
1078 *
1079 * free all rt debugging resources
1080 *
1081 * Return: none
1082 */
1083static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
1084{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001085 struct hdd_ipa_priv *hdd_ipa;
1086
1087 if (wlan_hdd_validate_context(hdd_ctx))
1088 return;
1089
1090 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001091
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301092 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093
1094 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001095 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096 return;
1097 }
1098
Anurag Chouhan210db072016-02-22 18:42:15 +05301099 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001100 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1101 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1102 }
1103 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1104
1105 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301106 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1107 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301109 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001110}
1111
1112/**
Yun Parkb187d542016-11-14 18:10:04 -08001113 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001114 * @hdd_ctx: hdd main context
1115 *
1116 * alloc and initialize all rt debugging resources
1117 *
1118 * Return: none
1119 */
1120static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
1121{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001122 struct hdd_ipa_priv *hdd_ipa;
1123
1124 if (wlan_hdd_validate_context(hdd_ctx))
1125 return;
1126
1127 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301129 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301131 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001132 sizeof(struct uc_rt_debug_info) *
1133 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1134 hdd_ipa->ipa_tx_forward = 0;
1135 hdd_ipa->ipa_rx_discard = 0;
1136 hdd_ipa->ipa_rx_net_send_count = 0;
1137 hdd_ipa->ipa_rx_internel_drop_count = 0;
1138 hdd_ipa->ipa_rx_destructor_count = 0;
1139
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140 /* Reatime debug enable on feature enable */
1141 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001142 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001143 return;
1144 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001145
1146 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1147 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1148 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1149 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1150
Anurag Chouhan210db072016-02-22 18:42:15 +05301151 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001152 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301153 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001154 HDD_IPA_UC_RT_DEBUG_PERIOD);
1155
1156}
1157
1158/**
Yun Parkb187d542016-11-14 18:10:04 -08001159 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1160 * @hdd_ipa: HDD IPA struct
1161 *
1162 * Dump entries in struct hdd_ipa
1163 *
1164 * Return: none
1165 */
1166static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1167{
1168 int i;
1169
1170 /* HDD IPA */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001171 hdd_info("==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001172 "num_iface: %d\n"
1173 "rm_state: %d\n"
1174 "rm_lock: %p\n"
1175 "uc_rm_work: %p\n"
1176 "uc_op_work: %p\n"
1177 "wake_lock: %p\n"
1178 "wake_lock_work: %p\n"
1179 "wake_lock_released: %d\n"
1180 "prod_client: %d\n"
1181 "tx_ref_cnt: %d\n"
1182 "pm_queue_head----\n"
1183 "\thead: %p\n"
1184 "\ttail: %p\n"
1185 "\tqlen: %d\n"
1186 "pm_work: %p\n"
1187 "pm_lock: %p\n"
1188 "suspended: %d\n",
1189 hdd_ipa->num_iface,
1190 hdd_ipa->rm_state,
1191 &hdd_ipa->rm_lock,
1192 &hdd_ipa->uc_rm_work,
1193 &hdd_ipa->uc_op_work,
1194 &hdd_ipa->wake_lock,
1195 &hdd_ipa->wake_lock_work,
1196 hdd_ipa->wake_lock_released,
1197 hdd_ipa->prod_client,
1198 hdd_ipa->tx_ref_cnt.counter,
1199 hdd_ipa->pm_queue_head.head,
1200 hdd_ipa->pm_queue_head.tail,
1201 hdd_ipa->pm_queue_head.qlen,
1202 &hdd_ipa->pm_work,
1203 &hdd_ipa->pm_lock,
1204 hdd_ipa->suspended);
Yun Park52b2b992016-09-22 15:49:51 -07001205 hdd_err("\nq_lock: %p\n"
Yun Parkb187d542016-11-14 18:10:04 -08001206 "pend_desc_head----\n"
1207 "\tnext: %p\n"
1208 "\tprev: %p\n"
1209 "hdd_ctx: %p\n"
1210 "debugfs_dir: %p\n"
1211 "stats: %p\n"
1212 "ipv4_notifier: %p\n"
1213 "curr_prod_bw: %d\n"
1214 "curr_cons_bw: %d\n"
1215 "activated_fw_pipe: %d\n"
1216 "sap_num_connected_sta: %d\n"
1217 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001218 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001219 hdd_ipa->pend_desc_head.next,
1220 hdd_ipa->pend_desc_head.prev,
1221 hdd_ipa->hdd_ctx,
1222 hdd_ipa->debugfs_dir,
1223 &hdd_ipa->stats,
1224 &hdd_ipa->ipv4_notifier,
1225 hdd_ipa->curr_prod_bw,
1226 hdd_ipa->curr_cons_bw,
1227 hdd_ipa->activated_fw_pipe,
1228 hdd_ipa->sap_num_connected_sta,
1229 (unsigned int)hdd_ipa->sta_connected
1230 );
Srinivas Girigowda97852372017-03-06 16:52:59 -08001231 hdd_info("\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001232 "rx_pipe_handle: 0x%x\n"
1233 "resource_loading: %d\n"
1234 "resource_unloading: %d\n"
1235 "pending_cons_req: %d\n"
1236 "pending_event----\n"
1237 "\tanchor.next: %p\n"
1238 "\tanchor.prev: %p\n"
1239 "\tcount: %d\n"
1240 "\tmax_size: %d\n"
1241 "event_lock: %p\n"
1242 "ipa_tx_packets_diff: %d\n"
1243 "ipa_rx_packets_diff: %d\n"
1244 "ipa_p_tx_packets: %d\n"
1245 "ipa_p_rx_packets: %d\n"
1246 "stat_req_reason: %d\n",
1247 hdd_ipa->tx_pipe_handle,
1248 hdd_ipa->rx_pipe_handle,
1249 hdd_ipa->resource_loading,
1250 hdd_ipa->resource_unloading,
1251 hdd_ipa->pending_cons_req,
1252 hdd_ipa->pending_event.anchor.next,
1253 hdd_ipa->pending_event.anchor.prev,
1254 hdd_ipa->pending_event.count,
1255 hdd_ipa->pending_event.max_size,
1256 &hdd_ipa->event_lock,
1257 hdd_ipa->ipa_tx_packets_diff,
1258 hdd_ipa->ipa_rx_packets_diff,
1259 hdd_ipa->ipa_p_tx_packets,
1260 hdd_ipa->ipa_p_rx_packets,
1261 hdd_ipa->stat_req_reason);
1262
Srinivas Girigowda97852372017-03-06 16:52:59 -08001263 hdd_info("assoc_stas_map([id]is_reserved/sta_id): ");
Yun Parkb187d542016-11-14 18:10:04 -08001264 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001265 hdd_info(" [%d]%d/%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001266 hdd_ipa->assoc_stas_map[i].is_reserved,
1267 hdd_ipa->assoc_stas_map[i].sta_id);
1268 }
1269}
1270
1271/**
1272 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1273 * @hdd_ipa: HDD IPA struct
1274 *
1275 * Dump entire struct hdd_ipa_sys_pipe
1276 *
1277 * Return: none
1278 */
1279static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1280{
1281 int i;
1282
1283 /* IPA SYS Pipes */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001284 hdd_info("==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001285
1286 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1287 struct hdd_ipa_sys_pipe *sys_pipe;
1288 struct ipa_sys_connect_params *ipa_sys_params;
1289
1290 sys_pipe = &hdd_ipa->sys_pipe[i];
1291 ipa_sys_params = &sys_pipe->ipa_sys_params;
1292
Srinivas Girigowda97852372017-03-06 16:52:59 -08001293 hdd_info("sys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001294 "\tconn_hdl: 0x%x\n"
1295 "\tconn_hdl_valid: %d\n"
1296 "\tnat_en: %d\n"
1297 "\thdr_len %d\n"
1298 "\thdr_additional_const_len: %d\n"
1299 "\thdr_ofst_pkt_size_valid: %d\n"
1300 "\thdr_ofst_pkt_size: %d\n"
1301 "\thdr_little_endian: %d\n"
1302 "\tmode: %d\n"
1303 "\tclient: %d\n"
1304 "\tdesc_fifo_sz: %d\n"
1305 "\tpriv: %p\n"
1306 "\tnotify: %p\n"
1307 "\tskip_ep_cfg: %d\n"
1308 "\tkeep_ipa_awake: %d\n",
1309 i,
1310 sys_pipe->conn_hdl,
1311 sys_pipe->conn_hdl_valid,
1312 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1313 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1314 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1315 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1316 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1317 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1318 ipa_sys_params->ipa_ep_cfg.mode.mode,
1319 ipa_sys_params->client,
1320 ipa_sys_params->desc_fifo_sz,
1321 ipa_sys_params->priv,
1322 ipa_sys_params->notify,
1323 ipa_sys_params->skip_ep_cfg,
1324 ipa_sys_params->keep_ipa_awake);
1325 }
1326}
1327
1328/**
1329 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1330 * @hdd_ipa: HDD IPA struct
1331 *
1332 * Dump entire struct hdd_ipa_iface_context
1333 *
1334 * Return: none
1335 */
1336static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1337{
1338 int i;
1339
1340 /* IPA Interface Contexts */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001341 hdd_info("==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001342
1343 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1344 struct hdd_ipa_iface_context *iface_context;
1345
1346 iface_context = &hdd_ipa->iface_context[i];
1347
Srinivas Girigowda97852372017-03-06 16:52:59 -08001348 hdd_info("iface_context[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001349 "\thdd_ipa: %p\n"
1350 "\tadapter: %p\n"
1351 "\ttl_context: %p\n"
1352 "\tcons_client: %d\n"
1353 "\tprod_client: %d\n"
1354 "\tiface_id: %d\n"
1355 "\tsta_id: %d\n"
1356 "\tinterface_lock: %p\n"
1357 "\tifa_address: 0x%x\n",
1358 i,
1359 iface_context->hdd_ipa,
1360 iface_context->adapter,
1361 iface_context->tl_context,
1362 iface_context->cons_client,
1363 iface_context->prod_client,
1364 iface_context->iface_id,
1365 iface_context->sta_id,
1366 &iface_context->interface_lock,
1367 iface_context->ifa_address);
1368 }
1369}
1370
1371/**
1372 * hdd_ipa_dump_info() - dump HDD IPA struct
1373 * @pHddCtx: hdd main context
1374 *
1375 * Dump entire struct hdd_ipa
1376 *
1377 * Return: none
1378 */
1379void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1380{
1381 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1382
1383 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1384 hdd_ipa_dump_sys_pipe(hdd_ipa);
1385 hdd_ipa_dump_iface_context(hdd_ipa);
1386}
1387
1388/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001389 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1390 * enabled
1391 *
1392 * This routine is called to set TX flow info if IPA is enabled
1393 *
1394 * Return: None
1395 */
1396void hdd_ipa_set_tx_flow_info(void)
1397{
1398 hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL;
1399 QDF_STATUS status;
1400 hdd_adapter_t *adapter;
1401 hdd_station_ctx_t *pHddStaCtx;
1402 hdd_ap_ctx_t *hdd_ap_ctx;
1403 hdd_hostapd_state_t *hostapd_state;
1404 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1405 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1406 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1407 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1408 const char *p2pMode = "DEV";
1409 hdd_context_t *hdd_ctx;
1410 cds_context_type *cds_ctx;
1411#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1412 uint8_t targetChannel = 0;
1413 uint8_t preAdapterChannel = 0;
1414 uint8_t channel24;
1415 uint8_t channel5;
1416 hdd_adapter_t *preAdapterContext = NULL;
1417 hdd_adapter_t *adapter2_4 = NULL;
1418 hdd_adapter_t *adapter5 = NULL;
1419 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1420#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1421 struct wlan_objmgr_psoc *psoc;
1422
1423 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1424 if (!hdd_ctx) {
1425 cds_err("HDD context is NULL");
1426 return;
1427 }
1428
1429 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1430 if (!cds_ctx) {
1431 cds_err("Invalid CDS Context");
1432 return;
1433 }
1434
1435 psoc = hdd_ctx->hdd_psoc;
1436 status = hdd_get_front_adapter(hdd_ctx, &adapterNode);
1437 while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) {
1438 adapter = adapterNode->pAdapter;
1439 switch (adapter->device_mode) {
1440 case QDF_STA_MODE:
1441 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1442 if (eConnectionState_Associated ==
1443 pHddStaCtx->conn_info.connState) {
1444 staChannel =
1445 pHddStaCtx->conn_info.operationChannel;
1446 qdf_copy_macaddr(&staBssid,
1447 &pHddStaCtx->conn_info.bssId);
1448#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1449 targetChannel = staChannel;
1450#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1451 }
1452 break;
1453 case QDF_P2P_CLIENT_MODE:
1454 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1455 if (eConnectionState_Associated ==
1456 pHddStaCtx->conn_info.connState) {
1457 p2pChannel =
1458 pHddStaCtx->conn_info.operationChannel;
1459 qdf_copy_macaddr(&p2pBssid,
1460 &pHddStaCtx->conn_info.bssId);
1461 p2pMode = "CLI";
1462#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1463 targetChannel = p2pChannel;
1464#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1465 }
1466 break;
1467 case QDF_P2P_GO_MODE:
1468 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1469 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1470 if (hostapd_state->bssState == BSS_START
1471 && hostapd_state->qdf_status ==
1472 QDF_STATUS_SUCCESS) {
1473 p2pChannel = hdd_ap_ctx->operatingChannel;
1474 qdf_copy_macaddr(&p2pBssid,
1475 &adapter->macAddressCurrent);
1476#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1477 targetChannel = p2pChannel;
1478#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1479 }
1480 p2pMode = "GO";
1481 break;
1482 case QDF_SAP_MODE:
1483 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1484 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1485 if (hostapd_state->bssState == BSS_START
1486 && hostapd_state->qdf_status ==
1487 QDF_STATUS_SUCCESS) {
1488 apChannel = hdd_ap_ctx->operatingChannel;
1489 qdf_copy_macaddr(&apBssid,
1490 &adapter->macAddressCurrent);
1491#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1492 targetChannel = apChannel;
1493#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1494 }
1495 break;
1496 case QDF_IBSS_MODE:
1497 default:
1498 break;
1499 }
1500#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1501 if (targetChannel) {
1502 /*
1503 * This is first adapter detected as active
1504 * set as default for none concurrency case
1505 */
1506 if (!preAdapterChannel) {
1507 /* If IPA UC data path is enabled,
1508 * target should reserve extra tx descriptors
1509 * for IPA data path.
1510 * Then host data path should allow less TX
1511 * packet pumping in case IPA
1512 * data path enabled
1513 */
1514 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1515 (QDF_SAP_MODE == adapter->device_mode)) {
1516 adapter->tx_flow_low_watermark =
1517 hdd_ctx->config->TxFlowLowWaterMark +
1518 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1519 } else {
1520 adapter->tx_flow_low_watermark =
1521 hdd_ctx->config->
1522 TxFlowLowWaterMark;
1523 }
1524 adapter->tx_flow_high_watermark_offset =
1525 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1526 cdp_fc_ll_set_tx_pause_q_depth(soc,
1527 adapter->sessionId,
1528 hdd_ctx->config->TxFlowMaxQueueDepth);
1529 cds_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
1530 adapter->device_mode,
1531 targetChannel,
1532 adapter->tx_flow_low_watermark,
1533 adapter->tx_flow_low_watermark +
1534 adapter->tx_flow_high_watermark_offset,
1535 hdd_ctx->config->TxFlowMaxQueueDepth);
1536 preAdapterChannel = targetChannel;
1537 preAdapterContext = adapter;
1538 } else {
1539 /*
1540 * SCC, disable TX flow control for both
1541 * SCC each adapter cannot reserve dedicated
1542 * channel resource, as a result, if any adapter
1543 * blocked OS Q by flow control,
1544 * blocked adapter will lost chance to recover
1545 */
1546 if (preAdapterChannel == targetChannel) {
1547 /* Current adapter */
1548 adapter->tx_flow_low_watermark = 0;
1549 adapter->
1550 tx_flow_high_watermark_offset = 0;
1551 cdp_fc_ll_set_tx_pause_q_depth(soc,
1552 adapter->sessionId,
1553 hdd_ctx->config->
1554 TxHbwFlowMaxQueueDepth);
1555 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1556 hdd_device_mode_to_string(
1557 adapter->device_mode),
1558 adapter->device_mode,
1559 targetChannel,
1560 adapter->tx_flow_low_watermark,
1561 adapter->tx_flow_low_watermark +
1562 adapter->
1563 tx_flow_high_watermark_offset,
1564 hdd_ctx->config->
1565 TxHbwFlowMaxQueueDepth);
1566
1567 if (!preAdapterContext) {
1568 cds_err("SCC: Previous adapter context NULL");
1569 continue;
1570 }
1571
1572 /* Previous adapter */
1573 preAdapterContext->
1574 tx_flow_low_watermark = 0;
1575 preAdapterContext->
1576 tx_flow_high_watermark_offset = 0;
1577 cdp_fc_ll_set_tx_pause_q_depth(soc,
1578 preAdapterContext->sessionId,
1579 hdd_ctx->config->
1580 TxHbwFlowMaxQueueDepth);
1581 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1582 hdd_device_mode_to_string(
1583 preAdapterContext->device_mode
1584 ),
1585 preAdapterContext->device_mode,
1586 targetChannel,
1587 preAdapterContext->
1588 tx_flow_low_watermark,
1589 preAdapterContext->
1590 tx_flow_low_watermark +
1591 preAdapterContext->
1592 tx_flow_high_watermark_offset,
1593 hdd_ctx->config->
1594 TxHbwFlowMaxQueueDepth);
1595 }
1596 /*
1597 * MCC, each adapter will have dedicated
1598 * resource
1599 */
1600 else {
1601 /* current channel is 2.4 */
1602 if (targetChannel <=
1603 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1604 channel24 = targetChannel;
1605 channel5 = preAdapterChannel;
1606 adapter2_4 = adapter;
1607 adapter5 = preAdapterContext;
1608 } else {
1609 /* Current channel is 5 */
1610 channel24 = preAdapterChannel;
1611 channel5 = targetChannel;
1612 adapter2_4 = preAdapterContext;
1613 adapter5 = adapter;
1614 }
1615
1616 if (!adapter5) {
1617 cds_err("MCC: 5GHz adapter context NULL");
1618 continue;
1619 }
1620 adapter5->tx_flow_low_watermark =
1621 hdd_ctx->config->
1622 TxHbwFlowLowWaterMark;
1623 adapter5->
1624 tx_flow_high_watermark_offset =
1625 hdd_ctx->config->
1626 TxHbwFlowHighWaterMarkOffset;
1627 cdp_fc_ll_set_tx_pause_q_depth(soc,
1628 adapter5->sessionId,
1629 hdd_ctx->config->
1630 TxHbwFlowMaxQueueDepth);
1631 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1632 hdd_device_mode_to_string(
1633 adapter5->device_mode),
1634 adapter5->device_mode,
1635 channel5,
1636 adapter5->tx_flow_low_watermark,
1637 adapter5->
1638 tx_flow_low_watermark +
1639 adapter5->
1640 tx_flow_high_watermark_offset,
1641 hdd_ctx->config->
1642 TxHbwFlowMaxQueueDepth);
1643
1644 if (!adapter2_4) {
1645 cds_err("MCC: 2.4GHz adapter context NULL");
1646 continue;
1647 }
1648 adapter2_4->tx_flow_low_watermark =
1649 hdd_ctx->config->
1650 TxLbwFlowLowWaterMark;
1651 adapter2_4->
1652 tx_flow_high_watermark_offset =
1653 hdd_ctx->config->
1654 TxLbwFlowHighWaterMarkOffset;
1655 cdp_fc_ll_set_tx_pause_q_depth(soc,
1656 adapter2_4->sessionId,
1657 hdd_ctx->config->
1658 TxLbwFlowMaxQueueDepth);
1659 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1660 hdd_device_mode_to_string(
1661 adapter2_4->device_mode),
1662 adapter2_4->device_mode,
1663 channel24,
1664 adapter2_4->
1665 tx_flow_low_watermark,
1666 adapter2_4->
1667 tx_flow_low_watermark +
1668 adapter2_4->
1669 tx_flow_high_watermark_offset,
1670 hdd_ctx->config->
1671 TxLbwFlowMaxQueueDepth);
1672
1673 }
1674 }
1675 }
1676 targetChannel = 0;
1677#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1678 status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext);
1679 adapterNode = pNext;
1680 }
1681 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1682}
1683
1684/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001685 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001687 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1688 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 *
1690 * Return: true if IPA is enabled, false otherwise
1691 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001692static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1694{
1695 struct hdd_ipa_priv *hdd_ipa;
1696
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 *ipa_tx_diff = 0;
1698 *ipa_rx_diff = 0;
1699
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001700 if (wlan_hdd_validate_context(hdd_ctx))
1701 return;
1702
1703 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1704
1705 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1706 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001707 return;
1708 }
1709
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301710 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1712 (false == hdd_ipa->resource_loading)) {
1713 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1714 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001715 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716 *ipa_tx_diff, *ipa_rx_diff);
1717 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301718 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001719}
1720
1721/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001722 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1723 * @hdd_ctx: Global HDD context
1724 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1725 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1726 *
1727 * Return: true if IPA is enabled, false otherwise
1728 */
1729void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1730 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1731{
1732 cds_ssr_protect(__func__);
1733 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1734 cds_ssr_unprotect(__func__);
1735}
1736
1737/**
1738 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001739 * @adapter: network adapter
1740 * @reason: STAT REQ Reason
1741 *
1742 * Return: None
1743 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001744static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001745{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001746 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001747 struct hdd_ipa_priv *hdd_ipa;
1748
Yun Park637d6482016-10-05 10:51:33 -07001749 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001750 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001751
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001752 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1753
1754 if (wlan_hdd_validate_context(hdd_ctx))
1755 return;
1756
1757 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1758 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1759 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001760 return;
1761 }
1762
Yun Parkb187d542016-11-14 18:10:04 -08001763 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301764 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001765 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1766 (false == hdd_ipa->resource_loading)) {
1767 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07001768 qdf_mutex_release(&hdd_ipa->ipa_lock);
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001769 sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter),
1770 adapter->sessionId,
1771 WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001772 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001773 } else {
1774 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001776}
1777
1778/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001779 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1780 * @adapter: network adapter
1781 * @reason: STAT REQ Reason
1782 *
1783 * Return: None
1784 */
1785void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1786{
1787 cds_ssr_protect(__func__);
1788 __hdd_ipa_uc_stat_request(adapter, reason);
1789 cds_ssr_unprotect(__func__);
1790}
1791
Yun Park637d6482016-10-05 10:51:33 -07001792#ifdef FEATURE_METERING
1793/**
1794 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
1795 * @adapter: network adapter
1796 * @reset_stats: reset stat countis after response
1797 *
1798 * Return: None
1799 */
1800void hdd_ipa_uc_sharing_stats_request(hdd_adapter_t *adapter,
1801 uint8_t reset_stats)
1802{
1803 hdd_context_t *pHddCtx;
1804 struct hdd_ipa_priv *hdd_ipa;
1805
1806 if (!adapter)
1807 return;
1808
1809 pHddCtx = adapter->pHddCtx;
1810 hdd_ipa = pHddCtx->hdd_ipa;
1811 if (!hdd_ipa_is_enabled(pHddCtx) ||
1812 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1813 return;
1814 }
1815
1816 HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats);
1817 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001818 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001819 qdf_mutex_release(&hdd_ipa->ipa_lock);
1820 wma_cli_set_command(
1821 (int)adapter->sessionId,
1822 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
1823 reset_stats, VDEV_CMD);
1824 } else {
1825 qdf_mutex_release(&hdd_ipa->ipa_lock);
1826 }
1827}
1828
1829/**
1830 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
1831 * @adapter: network adapter
1832 * @set_quota: when 1, FW starts quota monitoring
1833 * @quota_bytes: quota limit in bytes
1834 *
1835 * Return: None
1836 */
1837void hdd_ipa_uc_set_quota(hdd_adapter_t *adapter, uint8_t set_quota,
1838 uint64_t quota_bytes)
1839{
1840 hdd_context_t *pHddCtx;
1841 struct hdd_ipa_priv *hdd_ipa;
1842
1843 if (!adapter)
1844 return;
1845
1846 pHddCtx = adapter->pHddCtx;
1847 hdd_ipa = pHddCtx->hdd_ipa;
1848 if (!hdd_ipa_is_enabled(pHddCtx) ||
1849 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1850 return;
1851 }
1852
1853 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
1854 set_quota, quota_bytes);
1855
1856 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001857 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001858 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park327e7812017-02-14 15:18:10 -08001859 wma_cli_set2_command(
Yun Park637d6482016-10-05 10:51:33 -07001860 (int)adapter->sessionId,
1861 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
Yun Park327e7812017-02-14 15:18:10 -08001862 (set_quota ? quota_bytes&0xffffffff : 0),
1863 (set_quota ? quota_bytes>>32 : 0),
1864 VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001865 } else {
1866 qdf_mutex_release(&hdd_ipa->ipa_lock);
1867 }
1868}
1869#endif
1870
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001871/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001872 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1873 * @hdd_ipa: Global HDD IPA context
1874 * @sta_add: Should station be added
1875 * @sta_id: ID of the station being queried
1876 *
1877 * Return: true if the station was found
1878 */
1879static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1880 bool sta_add, uint8_t sta_id)
1881{
1882 bool sta_found = false;
1883 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001884
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1886 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1887 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1888 sta_found = true;
1889 break;
1890 }
1891 }
1892 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301893 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001894 "%s: STA ID %d already exist, cannot add",
1895 __func__, sta_id);
1896 return sta_found;
1897 }
1898 if (sta_add) {
1899 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1900 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1901 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1902 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1903 return sta_found;
1904 }
1905 }
1906 }
1907 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301908 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001909 "%s: STA ID %d does not exist, cannot delete",
1910 __func__, sta_id);
1911 return sta_found;
1912 }
1913 if (!sta_add) {
1914 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1915 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1916 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1917 hdd_ipa->assoc_stas_map[idx].is_reserved =
1918 false;
1919 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1920 return sta_found;
1921 }
1922 }
1923 }
1924 return sta_found;
1925}
1926
1927/**
1928 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1929 * @hdd_ipa: Global HDD IPA context
1930 *
1931 * Return: 0 on success, negative errno if error
1932 */
1933static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1934{
1935 int result;
1936 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001937 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001938
1939 /* ACTIVATE TX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001940 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001941 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1942 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001943 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1944 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301945 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946 "%s: Enable TX PIPE fail, code %d",
1947 __func__, result);
1948 return result;
1949 }
1950 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1951 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301952 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953 "%s: Resume TX PIPE fail, code %d",
1954 __func__, result);
1955 return result;
1956 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001957 cdp_ipa_set_active(soc,
1958 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1959 true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001960
1961 /* ACTIVATE RX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001962 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001963 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1964 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1966 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301967 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001968 "%s: Enable RX PIPE fail, code %d",
1969 __func__, result);
1970 return result;
1971 }
1972 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1973 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301974 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001975 "%s: Resume RX PIPE fail, code %d",
1976 __func__, result);
1977 return result;
1978 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001979 cdp_ipa_set_active(soc,
1980 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1981 true, false);
Leo Change3e49442015-10-26 20:07:13 -07001982 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983 return 0;
1984}
1985
1986/**
1987 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1988 * @hdd_ipa: Global HDD IPA context
1989 *
1990 * Return: 0 on success, negative errno if error
1991 */
1992static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1993{
1994 int result;
1995
Leo Change3e49442015-10-26 20:07:13 -07001996 hdd_ipa->ipa_pipes_down = true;
1997
Srinivas Girigowda97852372017-03-06 16:52:59 -08001998 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
2000 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302001 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002002 "%s: Suspend RX PIPE fail, code %d",
2003 __func__, result);
2004 return result;
2005 }
2006 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
2007 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302008 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002009 "%s: Disable RX PIPE fail, code %d",
2010 __func__, result);
2011 return result;
2012 }
2013
Srinivas Girigowda97852372017-03-06 16:52:59 -08002014 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
2016 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302017 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002018 "%s: Suspend TX PIPE fail, code %d",
2019 __func__, result);
2020 return result;
2021 }
2022 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
2023 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302024 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002025 "%s: Disable TX PIPE fail, code %d",
2026 __func__, result);
2027 return result;
2028 }
2029
2030 return 0;
2031}
2032
2033/**
2034 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
2035 * @hdd_ipa: Global HDD IPA context
2036 *
2037 * Return: 0 on success, negative errno if error
2038 */
2039static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
2040{
2041 hdd_ipa->activated_fw_pipe = 0;
2042 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07002043
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002044 /* If RM feature enabled
2045 * Request PROD Resource first
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002046 * PROD resource may return sync or async manners
2047 */
Yun Park4cab6ee2015-10-27 11:43:40 -07002048 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
2049 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
2050 /* RM PROD request sync return
2051 * enable pipe immediately
2052 */
2053 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302054 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07002055 "%s: IPA WDI Pipe activation failed",
2056 __func__);
2057 hdd_ipa->resource_loading = false;
2058 return -EBUSY;
2059 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002060 }
2061 } else {
2062 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07002063 * Just enabled all the PIPEs
2064 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002065 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302066 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07002067 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068 __func__);
2069 hdd_ipa->resource_loading = false;
2070 return -EBUSY;
2071 }
2072 hdd_ipa->resource_loading = false;
2073 }
Yun Park4cab6ee2015-10-27 11:43:40 -07002074
Srinivas Girigowda97852372017-03-06 16:52:59 -08002075 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07002076 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002077 return 0;
2078}
2079
2080/**
2081 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
2082 * @hdd_ipa: Global HDD IPA context
2083 *
2084 * Return: None
2085 */
2086static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
2087{
2088 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07002089 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002090
Yun Park7c4f31b2016-11-30 10:09:21 -08002091 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
2092 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2093 QDF_ASSERT(0);
2094 return;
2095 }
2096
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002097 hdd_ipa->resource_unloading = true;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002098 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW RX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002099 cdp_ipa_set_active(soc,
2100 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2101 false, false);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002102 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW TX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002103 cdp_ipa_set_active(soc,
2104 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2105 false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002106}
2107
2108/**
2109 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2110 * @context: User context registered with TL (the IPA Global context is
2111 * registered
2112 * @rxpkt: Packet containing the notification
2113 * @staid: ID of the station associated with the packet
2114 *
2115 * Return: None
2116 */
2117static void
2118hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
2119{
2120 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302121 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002122
2123 /*
2124 * When SSR is going on or driver is unloading, just return.
2125 */
2126 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302127 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002128 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002129
2130 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2131 return;
2132
Srinivas Girigowda97852372017-03-06 16:52:59 -08002133 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002134 __func__, event);
2135
2136 switch (event) {
2137 case IPA_RM_RESOURCE_GRANTED:
2138 /* Differed RM Granted */
2139 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302140 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002141 if ((false == hdd_ipa->resource_unloading) &&
2142 (!hdd_ipa->activated_fw_pipe)) {
2143 hdd_ipa_uc_enable_pipes(hdd_ipa);
2144 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302145 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002146 break;
2147
2148 case IPA_RM_RESOURCE_RELEASED:
2149 /* Differed RM Released */
2150 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002151 break;
2152
2153 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302154 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002155 "%s, invalid event code %d", __func__, event);
2156 break;
2157 }
2158}
2159
2160/**
2161 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2162 * @hdd_ipa: Global HDD IPA context
2163 * @event: IPA resource manager event to be deferred
2164 *
2165 * This function is called when a resource manager event is received
2166 * from firmware in interrupt context. This function will defer the
2167 * handling to the OL RX thread
2168 *
2169 * Return: None
2170 */
2171static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2172{
2173 enum ipa_rm_event event;
2174 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2175 struct uc_rm_work_struct, work);
2176 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2177 struct hdd_ipa_priv, uc_rm_work);
2178
2179 cds_ssr_protect(__func__);
2180 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002181 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002182 "%s, posted event %d", __func__, event);
2183
2184 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2185 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002186}
2187
2188/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002189 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2190 * @ipa_ctxt: hdd ipa local context
2191 *
2192 * Will handle IPA UC image loaded indication comes from IPA kernel
2193 *
2194 * Return: None
2195 */
2196static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt)
2197{
2198 struct ipa_wdi_out_params pipe_out;
2199
2200 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
2201 if (true == ipa_ctxt->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002202 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002203 __func__);
2204 return;
2205 }
2206
2207 ipa_ctxt->uc_loaded = true;
2208 /* Connect pipe */
2209 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2210 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2211 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
2212 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2213 "%s : TX PIPE Handle %d, DBPA 0x%llx",
2214 __func__, ipa_ctxt->tx_pipe_handle,
2215 (unsigned long long) pipe_out.uc_door_bell_pa);
2216
2217 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2218 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
2219 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2220 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2221 "%s : RX PIPE Handle %d, DBPA 0x%llx",
2222 __func__, ipa_ctxt->rx_pipe_handle,
2223 (unsigned long long) pipe_out.uc_door_bell_pa);
2224
2225 /* If already any STA connected, enable IPA/FW PIPEs */
2226 if (ipa_ctxt->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002227 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002228 "Client already connected, enable IPA/FW PIPEs");
2229 hdd_ipa_uc_handle_first_con(ipa_ctxt);
2230 }
2231}
2232
2233/**
Yun Park637d6482016-10-05 10:51:33 -07002234 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2235 * @hdd_ctx: Global HDD context
2236 * @op_msg: operation message received from firmware
2237 *
2238 * Return: QDF_STATUS enumeration
2239 */
2240#ifdef FEATURE_METERING
2241static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
2242 struct op_msg_type *op_msg)
2243{
2244 struct op_msg_type *msg = op_msg;
2245 struct ipa_uc_sharing_stats *uc_sharing_stats;
2246 struct ipa_uc_quota_rsp *uc_quota_rsp;
2247 struct ipa_uc_quota_ind *uc_quota_ind;
2248 struct hdd_ipa_priv *hdd_ipa;
2249 hdd_adapter_t *adapter;
2250
2251 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2252
2253 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2254 /* fill-up ipa_uc_sharing_stats structure from FW */
2255 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2256 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2257
2258 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2259 sizeof(struct ipa_uc_sharing_stats));
2260
2261 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2262
2263 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2264 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2265 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2266 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2267 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2268 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2269 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2270 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2271 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2272 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2273 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2274 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2275 /* received set quota response */
2276 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2277 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2278
2279 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2280 sizeof(struct ipa_uc_quota_rsp));
2281
2282 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2283 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2284 "%s: success=%d, quota_bytes=%llu",
2285 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2286 hdd_ipa->ipa_quota_rsp.success,
2287 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2288 hdd_ipa->ipa_quota_rsp.quota_lo);
2289 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2290 /* hit quota limit */
2291 uc_quota_ind = (struct ipa_uc_quota_ind *)
2292 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2293
2294 hdd_ipa->ipa_quota_ind.quota_bytes =
2295 uc_quota_ind->quota_bytes;
2296
2297 /* send quota exceeded indication to IPA */
2298 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2299 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2300 hdd_ipa->ipa_quota_ind.quota_bytes);
2301
2302 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2303 if (adapter)
2304 ipa_broadcast_wdi_quota_reach_ind(
2305 adapter->dev->ifindex,
2306 uc_quota_ind->quota_bytes);
2307 else
2308 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2309 "Failed quota_reach_ind: NULL adapter");
2310 } else {
2311 return QDF_STATUS_E_INVAL;
2312 }
2313
2314 return QDF_STATUS_SUCCESS;
2315}
2316#else
2317static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
2318 struct op_msg_type *op_msg)
2319{
2320 return QDF_STATUS_E_INVAL;
2321}
2322#endif
2323
2324/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002325 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2326 * @op_msg: operation message received from firmware
2327 * @usr_ctxt: user context registered with TL (we register the HDD Global
2328 * context)
2329 *
2330 * Return: None
2331 */
2332static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2333{
2334 struct op_msg_type *msg = op_msg;
2335 struct ipa_uc_fw_stats *uc_fw_stat;
2336 struct IpaHwStatsWDIInfoData_t ipa_stat;
2337 struct hdd_ipa_priv *hdd_ipa;
2338 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302339 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002340
2341 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302342 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002343 return;
2344 }
2345
2346 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302347 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002348 "%s, INVALID OPCODE %d", __func__, msg->op_code);
2349 return;
2350 }
2351
2352 hdd_ctx = (hdd_context_t *) usr_ctxt;
2353
2354 /*
2355 * When SSR is going on or driver is unloading, just return.
2356 */
2357 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302358 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302359 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002360 return;
2361 }
2362
2363 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2364
Govind Singhb6a89772016-08-12 11:23:35 +05302365 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002366 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002367
2368 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2369 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302370 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002371 hdd_ipa->activated_fw_pipe++;
2372 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2373 hdd_ipa->resource_loading = false;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002374 if (hdd_ipa->wdi_enabled == false) {
2375 hdd_ipa->wdi_enabled = true;
2376 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2377 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2378 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002379 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002380 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002381 if (hdd_ipa->pending_cons_req)
2382 ipa_rm_notify_completion(
2383 IPA_RM_RESOURCE_GRANTED,
2384 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002385 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002386 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302387 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002388 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002389 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302390 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002391 hdd_ipa->activated_fw_pipe--;
2392 if (!hdd_ipa->activated_fw_pipe) {
2393 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002394 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2395 ipa_rm_release_resource(
2396 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002397 /*
2398 * Sync return success from IPA
2399 * Enable/resume all the PIPEs
2400 */
Yun Park5b635012015-12-02 15:05:01 -08002401 hdd_ipa->resource_unloading = false;
2402 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2403 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002404 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302405 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002406 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002407 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002408 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002409 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302410 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002411 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002412 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002413 "CE RING SIZE: %d\n"
2414 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002415 (unsigned long long)res->ce_sr_base_paddr,
2416 res->ce_sr_ring_size,
2417 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302418 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002419 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002420 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002421 "COMP RING SIZE: %d\n"
2422 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002423 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002424 (unsigned long long)res->tx_comp_ring_base_paddr,
2425 res->tx_comp_ring_size,
2426 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08002427 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302428 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002429 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002430 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002431 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002432 "IND RING DBELL : 0x%llx\n"
2433 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002434 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08002435 "NUM TX FWD OK : %llu\n"
2436 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08002437 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002438 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08002439 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
2440 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002441 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08002442 hdd_ipa->stats.num_tx_fwd_ok,
2443 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302444 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002445 "==== IPA_UC WLAN_HOST CONTROL ====\n"
2446 "SAP NUM STAs: %d\n"
2447 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08002448 "CONCURRENT MODE: %s\n"
2449 "TX PIPE HDL: 0x%x\n"
2450 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002451 "RSC LOADING : %d\n"
2452 "RSC UNLOADING : %d\n"
2453 "PNDNG CNS RQT : %d",
2454 hdd_ipa->sap_num_connected_sta,
2455 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08002456 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002457 hdd_ipa->tx_pipe_handle,
2458 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08002459 hdd_ipa->resource_loading,
2460 hdd_ipa->resource_unloading,
2461 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002462
2463 /* STATs from FW */
2464 uc_fw_stat = (struct ipa_uc_fw_stats *)
2465 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302466 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002467 "==== IPA_UC WLAN_FW TX ====\n"
2468 "COMP RING BASE: 0x%x\n"
2469 "COMP RING SIZE: %d\n"
2470 "COMP RING DBELL : 0x%x\n"
2471 "COMP RING DBELL IND VAL : %d\n"
2472 "COMP RING DBELL CACHED VAL : %d\n"
2473 "COMP RING DBELL CACHED VAL : %d\n"
2474 "PKTS ENQ : %d\n"
2475 "PKTS COMP : %d\n"
2476 "IS SUSPEND : %d\n"
2477 "RSVD : 0x%x",
2478 uc_fw_stat->tx_comp_ring_base,
2479 uc_fw_stat->tx_comp_ring_size,
2480 uc_fw_stat->tx_comp_ring_dbell_addr,
2481 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2482 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2483 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2484 uc_fw_stat->tx_pkts_enqueued,
2485 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002486 uc_fw_stat->tx_is_suspend,
2487 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302488 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002489 "==== IPA_UC WLAN_FW RX ====\n"
2490 "IND RING BASE: 0x%x\n"
2491 "IND RING SIZE: %d\n"
2492 "IND RING DBELL : 0x%x\n"
2493 "IND RING DBELL IND VAL : %d\n"
2494 "IND RING DBELL CACHED VAL : %d\n"
2495 "RDY IND ADDR : 0x%x\n"
2496 "RDY IND CACHE VAL : %d\n"
2497 "RFIL IND : %d\n"
2498 "NUM PKT INDICAT : %d\n"
2499 "BUF REFIL : %d\n"
2500 "NUM DROP NO SPC : %d\n"
2501 "NUM DROP NO BUF : %d\n"
2502 "IS SUSPND : %d\n"
2503 "RSVD : 0x%x\n",
2504 uc_fw_stat->rx_ind_ring_base,
2505 uc_fw_stat->rx_ind_ring_size,
2506 uc_fw_stat->rx_ind_ring_dbell_addr,
2507 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2508 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2509 uc_fw_stat->rx_ind_ring_rdidx_addr,
2510 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2511 uc_fw_stat->rx_refill_idx,
2512 uc_fw_stat->rx_num_pkts_indicated,
2513 uc_fw_stat->rx_buf_refilled,
2514 uc_fw_stat->rx_num_ind_drop_no_space,
2515 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002516 uc_fw_stat->rx_is_suspend,
2517 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002518 /* STATs from IPA */
2519 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302520 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002521 "==== IPA_UC IPA TX ====\n"
2522 "NUM PROCD : %d\n"
2523 "CE DBELL : 0x%x\n"
2524 "NUM DBELL FIRED : %d\n"
2525 "COMP RNG FULL : %d\n"
2526 "COMP RNG EMPT : %d\n"
2527 "COMP RNG USE HGH : %d\n"
2528 "COMP RNG USE LOW : %d\n"
2529 "BAM FIFO FULL : %d\n"
2530 "BAM FIFO EMPT : %d\n"
2531 "BAM FIFO USE HGH : %d\n"
2532 "BAM FIFO USE LOW : %d\n"
2533 "NUM DBELL : %d\n"
2534 "NUM UNEXP DBELL : %d\n"
2535 "NUM BAM INT HDL : 0x%x\n"
2536 "NUM BAM INT NON-RUN : 0x%x\n"
2537 "NUM QMB INT HDL : 0x%x",
2538 ipa_stat.tx_ch_stats.num_pkts_processed,
2539 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2540 ipa_stat.tx_ch_stats.num_db_fired,
2541 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2542 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2543 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2544 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2545 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2546 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2547 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2548 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2549 ipa_stat.tx_ch_stats.num_db,
2550 ipa_stat.tx_ch_stats.num_unexpected_db,
2551 ipa_stat.tx_ch_stats.num_bam_int_handled,
2552 ipa_stat.tx_ch_stats.
2553 num_bam_int_in_non_runnning_state,
2554 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2555
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302556 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002557 "==== IPA_UC IPA RX ====\n"
2558 "MAX OST PKT : %d\n"
2559 "NUM PKT PRCSD : %d\n"
2560 "RNG RP : 0x%x\n"
2561 "COMP RNG FULL : %d\n"
2562 "COMP RNG EMPT : %d\n"
2563 "COMP RNG USE HGH : %d\n"
2564 "COMP RNG USE LOW : %d\n"
2565 "BAM FIFO FULL : %d\n"
2566 "BAM FIFO EMPT : %d\n"
2567 "BAM FIFO USE HGH : %d\n"
2568 "BAM FIFO USE LOW : %d\n"
2569 "NUM DB : %d\n"
2570 "NUM UNEXP DB : %d\n"
2571 "NUM BAM INT HNDL : 0x%x\n",
2572 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2573 ipa_stat.rx_ch_stats.num_pkts_processed,
2574 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2575 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2576 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2577 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2578 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2579 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2580 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2581 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2582 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2583 ipa_stat.rx_ch_stats.num_db,
2584 ipa_stat.rx_ch_stats.num_unexpected_db,
2585 ipa_stat.rx_ch_stats.num_bam_int_handled);
2586 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2587 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2588 /* STATs from FW */
2589 uc_fw_stat = (struct ipa_uc_fw_stats *)
2590 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302591 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002592 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2593 uc_fw_stat->tx_pkts_completed,
2594 hdd_ipa->ipa_p_tx_packets);
2595 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2596 (uc_fw_stat->rx_num_ind_drop_no_space +
2597 uc_fw_stat->rx_num_ind_drop_no_buf +
2598 uc_fw_stat->rx_num_pkts_indicated),
2599 hdd_ipa->ipa_p_rx_packets);
2600
2601 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2602 hdd_ipa->ipa_p_rx_packets =
2603 (uc_fw_stat->rx_num_ind_drop_no_space +
2604 uc_fw_stat->rx_num_ind_drop_no_buf +
2605 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302606 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002607 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2608 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2609 hdd_ipa_uc_loaded_handler(hdd_ipa);
2610 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002611 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2612 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2613 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002614 }
Yun Park8957d802017-01-25 12:27:29 -08002615
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302616 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002617}
2618
2619
2620/**
2621 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2622 * @adapter: device adapter instance
2623 * @offload_type: MCC or SCC
2624 * @enable: TX offload enable or disable
2625 *
2626 * Return: none
2627 */
2628static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002629 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002630{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002631 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002632 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002633 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002634 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002635
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002636 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637 return;
2638
Yun Park8292dcb2016-10-07 16:46:06 -07002639 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002640 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002641
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002642 if (!iface_context) {
2643 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2644 "Interface context is NULL");
2645 return;
2646 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08002647 if (session_id >= CSR_ROAM_SESSION_MAX) {
2648 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2649 "invalid session id: %d", session_id);
2650 return;
2651 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002652 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002653 /* IPA offload status is already set as desired */
2654 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002655 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
2656 "IPA offload status is already set",
2657 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002658 return;
2659 }
2660
Yun Park4540e862016-11-10 16:30:06 -08002661 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2662 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2663 "invalid session id: %d, offload_type=%d, enable=%d",
2664 adapter->sessionId, offload_type, enable);
2665 return;
2666 }
2667
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302668 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002669 sizeof(ipa_offload_enable_disable));
2670 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002671 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002672 ipa_offload_enable_disable.enable = enable;
2673
Srinivas Girigowda97852372017-03-06 16:52:59 -08002674 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park8292dcb2016-10-07 16:46:06 -07002675 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002676 ipa_offload_enable_disable.offload_type,
2677 ipa_offload_enable_disable.vdev_id,
2678 ipa_offload_enable_disable.enable);
2679
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302680 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002681 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2682 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302683 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002684 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2685 __func__,
2686 ipa_offload_enable_disable.offload_type,
2687 ipa_offload_enable_disable.vdev_id,
2688 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002689 } else {
2690 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002691 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002692 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002693 }
2694}
2695
2696/**
2697 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2698 * @work: uC OP work
2699 *
2700 * Return: None
2701 */
2702static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2703{
2704 struct op_msg_type *msg;
2705 struct uc_op_work_struct *uc_op_work = container_of(work,
2706 struct uc_op_work_struct, work);
2707 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2708
2709 cds_ssr_protect(__func__);
2710
2711 msg = uc_op_work->msg;
2712 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002713 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002714 "%s, posted msg %d", __func__, msg->op_code);
2715
2716 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2717
2718 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002719}
2720
2721/**
2722 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2723 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2724 * @op_msg: operation message received from firmware
2725 * @hdd_ctx: Global HDD context
2726 *
2727 * Return: None
2728 */
2729static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2730{
2731 struct hdd_ipa_priv *hdd_ipa;
2732 struct op_msg_type *msg;
2733 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302734 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002735
2736 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302737 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002738 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002739
2740 msg = (struct op_msg_type *)op_msg;
2741 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2742
2743 if (unlikely(!hdd_ipa))
2744 goto end;
2745
2746 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302747 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002748 __func__, msg->op_code);
2749 goto end;
2750 }
2751
2752 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2753 if (uc_op_work->msg)
2754 /* When the same uC OPCODE is already pended, just return */
2755 goto end;
2756
2757 uc_op_work->msg = msg;
2758 schedule_work(&uc_op_work->work);
2759 return;
2760
2761end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302762 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002763}
2764
2765/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002766 * hdd_ipa_init_uc_op_work - init ipa uc op work
2767 * @work: struct work_struct
2768 * @work_handler: work_handler
2769 *
2770 * Return: none
2771 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002772static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002773 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002774{
2775 INIT_WORK(work, work_handler);
2776}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002777
Yun Park637d6482016-10-05 10:51:33 -07002778#ifdef FEATURE_METERING
2779/**
2780 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2781 * IPA calls to get WLAN stats or set quota limit.
2782 * @priv: pointer to private data registered with IPA (we register a
2783 *» pointer to the global IPA context)
2784 * @evt: the IPA event which triggered the callback
2785 * @data: data associated with the event
2786 *
2787 * Return: None
2788 */
2789static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2790 void *data)
2791{
2792 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2793 hdd_adapter_t *adapter = NULL;
2794 struct ipa_get_wdi_sap_stats *wdi_sap_stats;
2795 struct ipa_set_wifi_quota *ipa_set_quota;
2796 int ret = 0;
2797
2798 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2799 return;
2800
2801 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2802
2803 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2804
2805 switch (evt) {
2806 case IPA_GET_WDI_SAP_STATS:
2807 /* fill-up ipa_get_wdi_sap_stats structure after getting
2808 ipa_uc_fw_stats from FW */
2809 wdi_sap_stats = data;
2810
2811 if (!adapter) {
2812 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2813 "IPA uC share stats failed - no adapter");
2814 wdi_sap_stats->stats_valid = 0;
2815 return;
2816 }
2817
2818 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
2819 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
2820 hdd_ipa_uc_sharing_stats_request(adapter,
2821 wdi_sap_stats->reset_stats);
2822 ret = wait_for_completion_timeout(
2823 &hdd_ipa->ipa_uc_sharing_stats_comp,
2824 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2825 if (!ret) {
2826 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2827 "IPA uC share stats request timed out");
2828 wdi_sap_stats->stats_valid = 0;
2829 } else {
2830 wdi_sap_stats->stats_valid = 1;
2831
2832 wdi_sap_stats->ipv4_rx_packets =
2833 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2834 wdi_sap_stats->ipv4_rx_bytes =
2835 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2836 wdi_sap_stats->ipv6_rx_packets =
2837 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2838 wdi_sap_stats->ipv6_rx_bytes =
2839 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
2840 wdi_sap_stats->ipv4_tx_packets =
2841 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
2842 wdi_sap_stats->ipv4_tx_bytes =
2843 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
2844 wdi_sap_stats->ipv6_tx_packets =
2845 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
2846 wdi_sap_stats->ipv6_tx_bytes =
2847 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
2848 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2849 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2850 "IPA_GET_WDI_SAP_STATS",
2851 wdi_sap_stats->stats_valid,
2852 wdi_sap_stats->ipv4_rx_packets,
2853 wdi_sap_stats->ipv4_rx_bytes,
2854 wdi_sap_stats->ipv6_rx_packets,
2855 wdi_sap_stats->ipv6_rx_bytes,
2856 wdi_sap_stats->ipv4_tx_packets,
2857 wdi_sap_stats->ipv4_tx_bytes,
2858 wdi_sap_stats->ipv6_tx_packets,
2859 wdi_sap_stats->ipv6_tx_bytes);
2860 }
2861 break;
2862 case IPA_SET_WIFI_QUOTA:
2863 /* get ipa_set_wifi_quota structure from IPA and pass to FW
2864 through quota_exceeded field in ipa_uc_fw_stats */
2865 ipa_set_quota = data;
2866
2867 if (!adapter) {
2868 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2869 "IPA uC set quota failed - no adapter");
2870 ipa_set_quota->set_valid = 0;
2871 return;
2872 }
2873
2874 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
2875 ipa_set_quota->quota_bytes);
2876
2877 ret = wait_for_completion_timeout(
2878 &hdd_ipa->ipa_uc_set_quota_comp,
2879 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
2880 if (!ret) {
2881 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2882 "IPA uC set quota request timed out");
2883 ipa_set_quota->set_valid = 0;
2884 } else {
2885 ipa_set_quota->quota_bytes =
2886 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
2887 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
2888 ipa_set_quota->set_valid =
2889 hdd_ipa->ipa_quota_rsp.success;
2890 }
2891
2892 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
2893 ipa_set_quota->quota_bytes,
2894 ipa_set_quota->set_valid);
2895 break;
2896 }
2897}
2898
2899/**
2900 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2901 * IPA calls to get WLAN stats or set quota limit.
2902 * @priv: pointer to private data registered with IPA (we register a
2903 *» pointer to the global IPA context)
2904 * @evt: the IPA event which triggered the callback
2905 * @data: data associated with the event
2906 *
2907 * Return: None
2908 */
2909static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2910 void *data)
2911{
2912 cds_ssr_protect(__func__);
2913 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
2914 cds_ssr_unprotect(__func__);
2915}
2916
2917static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt,
2918 struct ipa_wdi_in_params *pipe_in)
2919{
2920 pipe_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb;
2921
2922 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
2923 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
2924}
2925#else
2926static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt,
2927 struct ipa_wdi_in_params *pipe_in)
2928{
2929}
2930#endif
2931
Rajeev Kumar217f2172016-01-06 18:11:55 -08002932/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002933 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2934 * @hdd_ctx: Global HDD context
2935 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002936 * This function is called to update IPA pipe configuration with resources
2937 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
2938 * (cds_enable)
2939 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302940 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002941 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002942QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002943{
2944 struct ipa_wdi_in_params pipe_in;
2945 struct ipa_wdi_out_params pipe_out;
2946 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07002947 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002948 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2949 int ret;
2950 QDF_STATUS stat = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002951
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002952 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2953 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002954
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002955 ENTER();
2956 /* Do only IPA Pipe specific configuration here. All one time
2957 * initialization wrt IPA UC shall in hdd_ipa_init and those need
2958 * to be reinit at SSR shall in be SSR deinit / reinit functions.
2959 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002960 if (!pdev || !soc) {
2961 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkbaa62862017-01-18 13:43:34 -08002962 stat = QDF_STATUS_E_FAILURE;
2963 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002964 }
Yun Parkbaa62862017-01-18 13:43:34 -08002965
2966 cdp_ipa_get_resource(soc, (void *)pdev, &ipa_ctxt->ipa_resource);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002967 if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) ||
2968 (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2969 (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2970 (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2971 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2972 "IPA UC resource alloc fail");
2973 return QDF_STATUS_E_FAILURE;
2974 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002975 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2976 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302977 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2978 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002979
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002980 /* TX PIPE */
2981 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2982 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2983 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2984 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2985 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2986 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2987 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2988 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2989 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2990 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2991 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2992 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2993 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002994 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2995 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002996 pipe_in.sys.keep_ipa_awake = true;
2997 }
2998
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002999 pipe_in.u.dl.comp_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003000 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Yun Park034e9782017-01-23 16:17:11 -08003001 /* IPA requires total byte counts of Tx comp ring */
Leo Chang3bc8fed2015-11-13 10:59:47 -08003002 pipe_in.u.dl.comp_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003003 ipa_ctxt->ipa_resource.tx_comp_ring_size *
3004 sizeof(qdf_dma_addr_t);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003005 pipe_in.u.dl.ce_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003006 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003007 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
3008 pipe_in.u.dl.ce_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003009 ipa_ctxt->ipa_resource.ce_sr_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003010 pipe_in.u.dl.num_tx_buffers =
Yun Parkbaa62862017-01-18 13:43:34 -08003011 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003012
Yun Parkbaa62862017-01-18 13:43:34 -08003013 qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in,
3014 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003015 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08003016 IPA_CLIENT_WLAN1_CONS);
3017
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003018 if (true == ipa_ctxt->uc_loaded) {
3019 /* Connect WDI IPA PIPE */
Yun Parkbaa62862017-01-18 13:43:34 -08003020 ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
3021 if (ret) {
3022 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3023 "ipa_connect_wdi_pipe falied for Tx: ret=%d",
3024 ret);
3025 stat = QDF_STATUS_E_FAILURE;
3026 goto fail_return;
3027 }
Yun Park637d6482016-10-05 10:51:33 -07003028
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003029 /* Micro Controller Doorbell register */
Srinivas Girigowda97852372017-03-06 16:52:59 -08003030 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003031 "CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
3032 (unsigned int)pipe_out.uc_door_bell_pa,
3033 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003034 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Yun Parkbaa62862017-01-18 13:43:34 -08003035
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003036 /* WLAN TX PIPE Handle */
3037 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08003038 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003039 "TX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x, %s %d, %s %d, %s 0x%x",
3040 "comp_ring_base_pa",
3041 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
3042 "comp_ring_size",
3043 pipe_in.u.dl.comp_ring_size,
3044 "ce_ring_base_pa",
3045 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
3046 "ce_door_bell_pa",
3047 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
3048 "ce_ring_size",
3049 pipe_in.u.dl.ce_ring_size,
3050 "num_tx_buffers",
3051 pipe_in.u.dl.num_tx_buffers,
3052 "tx_comp_doorbell_paddr",
3053 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003054 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055
3056 /* RX PIPE */
3057 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3058 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
3059 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
3060 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
3061 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
3062 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
3063 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
3064 sizeof(struct sps_iovec);
3065 pipe_in.sys.notify = hdd_ipa_w2i_cb;
3066 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303067 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkbaa62862017-01-18 13:43:34 -08003068 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003069 pipe_in.sys.keep_ipa_awake = true;
3070 }
3071
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003072 pipe_in.u.ul.rdy_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003073 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003074 pipe_in.u.ul.rdy_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003075 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003076 pipe_in.u.ul.rdy_ring_rp_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003077 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003078 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Yun Parkbaa62862017-01-18 13:43:34 -08003079
Yun Park637d6482016-10-05 10:51:33 -07003080 hdd_ipa_init_metering(ipa_ctxt, &pipe_in);
3081
Yun Parkbaa62862017-01-18 13:43:34 -08003082 qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in,
3083 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003084 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08003085 IPA_CLIENT_WLAN1_PROD);
3086
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003087 if (true == ipa_ctxt->uc_loaded) {
Yun Parkbaa62862017-01-18 13:43:34 -08003088 ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
3089 if (ret) {
3090 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3091 "ipa_connect_wdi_pipe falied for Rx: ret=%d",
3092 ret);
3093 stat = QDF_STATUS_E_FAILURE;
3094 goto fail_return;
3095
3096 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003097 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
3098 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08003099 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08003100 "PROD DB pipe out 0x%x TX PIPE Handle 0x%x",
3101 (unsigned int)pipe_out.uc_door_bell_pa,
3102 ipa_ctxt->tx_pipe_handle);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003103 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003104 "RX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x",
3105 "rdy_ring_base_pa",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003106 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
Yun Park637d6482016-10-05 10:51:33 -07003107 "rdy_ring_size",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003108 pipe_in.u.ul.rdy_ring_size,
Yun Park637d6482016-10-05 10:51:33 -07003109 "rdy_ring_rp_pa",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003110 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
Yun Park637d6482016-10-05 10:51:33 -07003111 "rx_ready_doorbell_paddr",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003112 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
3113 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003114
Yun Parkbaa62862017-01-18 13:43:34 -08003115 cdp_ipa_set_doorbell_paddr(soc, (void *)pdev,
3116 ipa_ctxt->tx_comp_doorbell_paddr,
3117 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003118
Yun Parkbaa62862017-01-18 13:43:34 -08003119 cdp_ipa_register_op_cb(soc, (void *)pdev,
3120 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
3121
3122 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
3123 "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x",
3124 pdev->ipa_uc_op_cb,
3125 (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr,
3126 (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003127
Yun Parkbaa62862017-01-18 13:43:34 -08003128fail_return:
3129 EXIT();
3130 return stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003131}
3132
Leo Change3e49442015-10-26 20:07:13 -07003133/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303134 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
3135 * @hdd_ctx: Global HDD context
3136 *
3137 * Return: 0 on success, negativer errno on error
3138 */
3139int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx)
3140{
3141 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
3142 int ret = 0;
3143
3144 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3145 return ret;
3146
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05303147 if (!hdd_ipa->ipa_pipes_down)
3148 hdd_ipa_uc_disable_pipes(hdd_ipa);
3149
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303150 if (true == hdd_ipa->uc_loaded) {
3151 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
3152 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
3153 __func__, hdd_ipa->tx_pipe_handle);
3154 ret = ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
3155 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
3156 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
3157 __func__, hdd_ipa->rx_pipe_handle);
3158 ret = ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
3159 }
3160
3161 return ret;
3162}
3163
3164/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003165 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07003166 * @hdd_ctx: hdd main context
3167 *
3168 * Force shutdown IPA pipe
3169 * Independent of FW pipe status, IPA pipe shutdonw progress
3170 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3171 * independent from FW pipe status
3172 *
3173 * Return: NONE
3174 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003175static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07003176{
3177 struct hdd_ipa_priv *hdd_ipa;
3178
3179 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
3180 return;
3181
3182 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
3183 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303184 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07003185 "IPA pipes are not down yet, force shutdown");
3186 hdd_ipa_uc_disable_pipes(hdd_ipa);
3187 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003188 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Leo Change3e49442015-10-26 20:07:13 -07003189 "IPA pipes are down, do nothing");
3190 }
Leo Change3e49442015-10-26 20:07:13 -07003191}
3192
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003193/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003194 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
3195 * __hdd_ipa_uc_force_pipe_shutdown
3196 * @hdd_ctx: hdd main context
3197 *
3198 * Force shutdown IPA pipe
3199 * Independent of FW pipe status, IPA pipe shutdonw progress
3200 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3201 * independent from FW pipe status
3202 *
3203 * Return: NONE
3204 */
3205void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
3206{
3207 cds_ssr_protect(__func__);
3208 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
3209 cds_ssr_unprotect(__func__);
3210}
3211
3212/**
Govind Singh9c58eba2016-09-02 16:23:06 +05303213 * hdd_ipa_msg_free_fn() - Free an IPA message
3214 * @buff: pointer to the IPA message
3215 * @len: length of the IPA message
3216 * @type: type of IPA message
3217 *
3218 * Return: None
3219 */
3220static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
3221{
Srinivas Girigowda97852372017-03-06 16:52:59 -08003222 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05303223 ghdd_ipa->stats.num_free_msg++;
3224 qdf_mem_free(buff);
3225}
3226
Govind Singh9c58eba2016-09-02 16:23:06 +05303227/**
jge62037862016-12-09 10:44:33 +08003228 * hdd_ipa_uc_send_evt() - send event to ipa
3229 * @hdd_ctx: pointer to hdd context
3230 * @type: event type
3231 * @mac_addr: pointer to mac address
3232 *
3233 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303234 *
3235 * Return: 0 - Success
3236 */
jge62037862016-12-09 10:44:33 +08003237static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
3238 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303239{
jge62037862016-12-09 10:44:33 +08003240 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05303241 struct ipa_msg_meta meta;
3242 struct ipa_wlan_msg *msg;
3243 int ret = 0;
jge62037862016-12-09 10:44:33 +08003244
3245 meta.msg_len = sizeof(struct ipa_wlan_msg);
3246 msg = qdf_mem_malloc(meta.msg_len);
3247 if (msg == NULL) {
3248 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3249 "msg allocation failed");
3250 return -ENOMEM;
3251 }
3252
3253 meta.msg_type = type;
3254 strlcpy(msg->name, adapter->dev->name,
3255 IPA_RESOURCE_NAME_MAX);
3256 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003257 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
jge62037862016-12-09 10:44:33 +08003258 msg->name, meta.msg_type);
3259 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
3260 if (ret) {
3261 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3262 "%s: Evt: %d fail:%d",
3263 msg->name, meta.msg_type, ret);
3264 qdf_mem_free(msg);
3265 return ret;
3266 }
3267
3268 hdd_ipa->stats.num_send_msg++;
3269
3270 return ret;
3271}
3272
3273/**
3274 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3275 * @hdd_ctx: pointer to hdd adapter
3276 *
3277 * Send disconnect client event to IPA driver during SSR
3278 *
3279 * Return: 0 - Success
3280 */
3281static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
3282{
3283 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3284 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303285 int i;
3286
3287 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
3288 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
3289 continue;
3290 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08003291 (!adapter->aStaInfo[i].isDeauthInProgress) &&
3292 hdd_ipa->sap_num_connected_sta) {
3293 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
3294 adapter->aStaInfo[i].macAddrSTA.bytes);
3295 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303296 }
3297 }
3298
3299 return ret;
3300}
3301
3302/**
jge62037862016-12-09 10:44:33 +08003303 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3304 * @hdd_ctx: pointer to hdd adapter
3305 *
3306 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303307 *
3308 * Return: 0 - Success
3309 */
jge62037862016-12-09 10:44:33 +08003310
3311static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
3312{
3313 int ret = 0;
3314
3315 if (adapter->ipa_context)
3316 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3317 adapter->dev->dev_addr);
3318
3319 return ret;
3320}
3321
jge62037862016-12-09 10:44:33 +08003322/**
3323 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3324 * @hdd_ctx: pointer to hdd adapter
3325 *
3326 * Send disconnect sta event to IPA driver during SSR
3327 *
3328 * Return: 0 - Success
3329 */
3330static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
3331{
3332 hdd_station_ctx_t *pHddStaCtx;
3333 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3334 int ret = 0;
3335
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003336 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003337 hdd_ipa->sta_connected) {
3338 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
3339 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003340 pHddStaCtx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003341 }
3342
3343 return ret;
3344}
jge62037862016-12-09 10:44:33 +08003345
3346/**
3347 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3348 * @hdd_ctx: pointer to hdd context
3349 *
3350 * Send disconnect event to IPA driver during SSR
3351 *
3352 * Return: 0 - Success
3353 */
3354static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303355{
3356 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
3357 QDF_STATUS status;
3358 hdd_adapter_t *adapter;
3359 int ret = 0;
3360
Govind Singh9c58eba2016-09-02 16:23:06 +05303361 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
3362 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
3363 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08003364 if (adapter->device_mode == QDF_SAP_MODE) {
3365 hdd_ipa_uc_disconnect_client(adapter);
3366 hdd_ipa_uc_disconnect_ap(adapter);
3367 } else if (adapter->device_mode == QDF_STA_MODE) {
3368 hdd_ipa_uc_disconnect_sta(adapter);
3369 }
3370
Govind Singh9c58eba2016-09-02 16:23:06 +05303371 status = hdd_get_next_adapter(
3372 hdd_ctx, adapter_node, &next);
3373 adapter_node = next;
3374 }
3375
3376 return ret;
3377}
3378
3379/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003380 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003381 *
3382 * Deinit basic IPA UC host side to be in sync reloaded FW during
3383 * SSR
3384 *
3385 * Return: 0 - Success
3386 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003387static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003388{
3389 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3390 int idx;
3391 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303392 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003393
Arun Khandavallicc544b32017-01-30 19:52:16 +05303394 if (!hdd_ipa)
3395 return 0;
3396
3397 hdd_ctx = hdd_ipa->hdd_ctx;
3398 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003399 return 0;
3400
jge62037862016-12-09 10:44:33 +08003401 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303402 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003403
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003404 /* Clean up HDD IPA interfaces */
3405 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3406 (idx < HDD_IPA_MAX_IFACE); idx++) {
3407 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003408 if (iface_context->adapter && iface_context->adapter->magic ==
3409 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410 hdd_ipa_cleanup_iface(iface_context);
3411 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003412 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413 /* After SSR, wlan driver reloads FW again. But we need to protect
3414 * IPA submodule during SSR transient state. So deinit basic IPA
3415 * UC host side to be in sync with reloaded FW during SSR
3416 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003417
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303418 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003419 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3420 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3421 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3422 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303423 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003424
Guolei Bianca144d82016-11-10 11:07:42 +08003425 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3426 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3427
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003428 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
3429 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
3430 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
3431 hdd_ipa->uc_op_work[idx].msg = NULL;
3432 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433 return 0;
3434}
3435
3436/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003437 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3438 *
3439 * Deinit basic IPA UC host side to be in sync reloaded FW during
3440 * SSR
3441 *
3442 * Return: 0 - Success
3443 */
3444int hdd_ipa_uc_ssr_deinit(void)
3445{
3446 int ret;
3447
3448 cds_ssr_protect(__func__);
3449 ret = __hdd_ipa_uc_ssr_deinit();
3450 cds_ssr_unprotect(__func__);
3451
3452 return ret;
3453}
3454
3455/**
3456 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457 *
3458 * Init basic IPA UC host side to be in sync with reloaded FW after
3459 * SSR to resume IPA UC operations
3460 *
3461 * Return: 0 - Success
3462 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303463static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003464{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003465
Arun Khandavallicc544b32017-01-30 19:52:16 +05303466 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3467 int i;
3468 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303469
3470 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3471 return 0;
3472
Arun Khandavallicc544b32017-01-30 19:52:16 +05303473 /* Create the interface context */
3474 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3475 iface_context = &hdd_ipa->iface_context[i];
3476 iface_context->hdd_ipa = hdd_ipa;
3477 iface_context->cons_client =
3478 hdd_ipa_adapter_2_client[i].cons_client;
3479 iface_context->prod_client =
3480 hdd_ipa_adapter_2_client[i].prod_client;
3481 iface_context->iface_id = i;
3482 iface_context->adapter = NULL;
3483 }
3484 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3485 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3486 hdd_ipa->vdev_offload_enabled[i] = false;
3487 }
3488
3489 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3490 hdd_ipa->resource_loading = false;
3491 hdd_ipa->resource_unloading = false;
3492 hdd_ipa->sta_connected = 0;
3493 hdd_ipa->ipa_pipes_down = true;
3494 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303495 }
3496
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003497 return 0;
3498}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003499
3500/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003501 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3502 *
3503 * Init basic IPA UC host side to be in sync with reloaded FW after
3504 * SSR to resume IPA UC operations
3505 *
3506 * Return: 0 - Success
3507 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303508int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003509{
3510 int ret;
3511
3512 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303513 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003514 cds_ssr_unprotect(__func__);
3515
3516 return ret;
3517}
3518
3519/**
3520 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08003521 * @hdd_ctx: Global HDD context
3522 * @skb: skb sent to IPA
3523 * @session_id: send packet instance session id
3524 *
3525 * Send TX packet which generated by system to IPA.
3526 * This routine only will be used for function verification
3527 *
3528 * Return: NULL packet sent to IPA properly
3529 * NULL invalid packet drop
3530 * skb packet not sent to IPA. legacy data path should handle
3531 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003532static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08003533 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07003534{
Leo Chang3bc8fed2015-11-13 10:59:47 -08003535 struct ipa_header *ipa_header;
3536 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003537 struct hdd_ipa_priv *hdd_ipa;
3538
3539 if (wlan_hdd_validate_context(hdd_ctx))
3540 return skb;
3541
3542 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003543
3544 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3545 return skb;
3546
Leo Chang07b28f62016-05-11 12:29:22 -07003547 if (!hdd_ipa)
3548 return skb;
3549
3550 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
3551 return skb;
3552
Leo Changcc923e22016-06-16 15:29:03 -07003553 if (skb_headroom(skb) <
3554 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07003555 return skb;
3556
Leo Chang3bc8fed2015-11-13 10:59:47 -08003557 ipa_header = (struct ipa_header *) skb_push(skb,
3558 sizeof(struct ipa_header));
3559 if (!ipa_header) {
3560 /* No headroom, legacy */
3561 return skb;
3562 }
3563 memset(ipa_header, 0, sizeof(*ipa_header));
3564 ipa_header->vdev_id = 0;
3565
3566 frag_header = (struct frag_header *) skb_push(skb,
3567 sizeof(struct frag_header));
3568 if (!frag_header) {
3569 /* No headroom, drop */
3570 kfree_skb(skb);
3571 return NULL;
3572 }
3573 memset(frag_header, 0, sizeof(*frag_header));
3574 frag_header->length = skb->len - sizeof(struct frag_header)
3575 - sizeof(struct ipa_header);
3576
3577 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
3578 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07003579}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003580
3581/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003582 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
3583 * @hdd_ctx: Global HDD context
3584 * @skb: skb sent to IPA
3585 * @session_id: send packet instance session id
3586 *
3587 * Send TX packet which generated by system to IPA.
3588 * This routine only will be used for function verification
3589 *
3590 * Return: NULL packet sent to IPA properly
3591 * NULL invalid packet drop
3592 * skb packet not sent to IPA. legacy data path should handle
3593 */
3594struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
3595 struct sk_buff *skb, uint8_t session_id)
3596{
3597 struct sk_buff *ret;
3598
3599 cds_ssr_protect(__func__);
3600 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
3601 cds_ssr_unprotect(__func__);
3602
3603 return ret;
3604}
3605
3606/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003607 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3608 * @work: scheduled work
3609 *
3610 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3611 * not want to immediately release the wake lock since the system
3612 * would then potentially try to suspend when there is a healthy data
3613 * rate. Deferred work is scheduled and this function handles the
3614 * work. When this function is called, if the IPA resource is still
3615 * released then we release the wake lock.
3616 *
3617 * Return: None
3618 */
3619static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3620{
3621 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3622 struct hdd_ipa_priv,
3623 wake_lock_work);
3624
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303625 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003626
3627 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3628 goto end;
3629
3630 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303631 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003632 WIFI_POWER_EVENT_WAKELOCK_IPA);
3633
3634end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303635 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636}
3637
3638/**
3639 * hdd_ipa_rm_request() - Request resource from IPA
3640 * @hdd_ipa: Global HDD IPA context
3641 *
3642 * Return: 0 on success, negative errno on error
3643 */
3644static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3645{
3646 int ret = 0;
3647
3648 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3649 return 0;
3650
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303651 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003652
3653 switch (hdd_ipa->rm_state) {
3654 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303655 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003656 return 0;
3657 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303658 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003659 return -EINPROGRESS;
3660 case HDD_IPA_RM_RELEASED:
3661 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3662 break;
3663 }
3664
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303665 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003666
3667 ret = ipa_rm_inactivity_timer_request_resource(
3668 IPA_RM_RESOURCE_WLAN_PROD);
3669
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303670 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003671 if (ret == 0) {
3672 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3673 hdd_ipa->stats.num_rm_grant_imm++;
3674 }
3675
3676 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3677 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303678 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003679 WIFI_POWER_EVENT_WAKELOCK_IPA);
3680 hdd_ipa->wake_lock_released = false;
3681 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303682 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003683
3684 return ret;
3685}
3686
3687/**
3688 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3689 * @hdd_ipa: Global HDD IPA context
3690 *
3691 * Return: 0 if resources released, negative errno otherwise
3692 */
3693static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3694{
3695 int ret = 0;
3696
3697 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3698 return 0;
3699
3700 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3701 return -EAGAIN;
3702
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303703 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003704
Nirav Shahcbc6d722016-03-01 16:24:53 +05303705 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303706 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707 return -EAGAIN;
3708 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303709 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003710
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303711 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003712 switch (hdd_ipa->rm_state) {
3713 case HDD_IPA_RM_GRANTED:
3714 break;
3715 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303716 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003717 return -EINPROGRESS;
3718 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303719 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003720 return 0;
3721 }
3722
3723 /* IPA driver returns immediately so set the state here to avoid any
3724 * race condition.
3725 */
3726 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3727 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303728 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003729
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003730 ret = ipa_rm_inactivity_timer_release_resource(
3731 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003732
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303733 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003734 if (unlikely(ret != 0)) {
3735 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3736 WARN_ON(1);
3737 }
3738
3739 /*
3740 * If wake_lock is released immediately, kernel would try to suspend
3741 * immediately as well, Just avoid ping-pong between suspend-resume
3742 * while there is healthy amount of data transfer going on by
3743 * releasing the wake_lock after some delay.
3744 */
3745 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3746 msecs_to_jiffies
3747 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3748
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303749 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003750
3751 return ret;
3752}
3753
3754/**
3755 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3756 * @user_data: user data registered with IPA
3757 * @event: the IPA resource manager event that occurred
3758 * @data: the data associated with the event
3759 *
3760 * Return: None
3761 */
3762static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3763 unsigned long data)
3764{
3765 struct hdd_ipa_priv *hdd_ipa = user_data;
3766
3767 if (unlikely(!hdd_ipa))
3768 return;
3769
3770 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3771 return;
3772
Srinivas Girigowda97852372017-03-06 16:52:59 -08003773 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003774
3775 switch (event) {
3776 case IPA_RM_RESOURCE_GRANTED:
3777 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3778 /* RM Notification comes with ISR context
3779 * it should be serialized into work queue to avoid
3780 * ISR sleep problem
3781 */
3782 hdd_ipa->uc_rm_work.event = event;
3783 schedule_work(&hdd_ipa->uc_rm_work.work);
3784 break;
3785 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303786 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003787 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303788 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003789 hdd_ipa->stats.num_rm_grant++;
3790 break;
3791
3792 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003793 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003794 hdd_ipa->resource_unloading = false;
3795 break;
3796
3797 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303798 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003799 break;
3800 }
3801}
3802
3803/**
3804 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3805 *
3806 * Callback function registered with IPA that is called when IPA wants
3807 * to release the WLAN consumer resource
3808 *
3809 * Return: 0 if the request is granted, negative errno otherwise
3810 */
3811static int hdd_ipa_rm_cons_release(void)
3812{
3813 return 0;
3814}
3815
3816/**
3817 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3818 *
3819 * Callback function registered with IPA that is called when IPA wants
3820 * to access the WLAN consumer resource
3821 *
3822 * Return: 0 if the request is granted, negative errno otherwise
3823 */
3824static int hdd_ipa_rm_cons_request(void)
3825{
Yun Park4d8b60a2015-10-22 13:59:32 -07003826 int ret = 0;
3827
3828 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303829 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003830 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003831 __func__);
3832 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003833 ret = -EINPROGRESS;
3834 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303835 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003836 "%s: IPA resource unloading in progress",
3837 __func__);
3838 ghdd_ipa->pending_cons_req = true;
3839 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003840 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003841
3842 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003843}
3844
3845/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003846 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003847 * @hdd_ctx: Global HDD context
3848 * @tx_packets: Number of packets transmitted in the last sample period
3849 * @rx_packets: Number of packets received in the last sample period
3850 *
3851 * Return: 0 on success, negative errno on error
3852 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003853static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003854 uint64_t rx_packets)
3855{
3856 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003857 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858 struct ipa_rm_perf_profile profile;
3859 int ret;
3860
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003861 if (wlan_hdd_validate_context(hdd_ctx))
3862 return 0;
3863
3864 hdd_ipa = hdd_ctx->hdd_ipa;
3865
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003866 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3867 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3868 return 0;
3869
3870 memset(&profile, 0, sizeof(profile));
3871
3872 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3873 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3874 else if (tx_packets >
3875 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3876 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3877 else
3878 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3879
3880 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3881 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3882 else if (rx_packets >
3883 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3884 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3885 else
3886 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3887
Yun Parkec845302016-12-15 09:22:57 -08003888 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003889 "CONS perf curr: %d, next: %d",
3890 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003891 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003892 "PROD perf curr: %d, next: %d",
3893 hdd_ipa->curr_prod_bw, next_prod_bw);
3894
3895 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003896 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897 hdd_ipa->curr_cons_bw, next_cons_bw);
3898 profile.max_supported_bandwidth_mbps = next_cons_bw;
3899 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3900 &profile);
3901 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003902 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903
3904 return ret;
3905 }
3906 hdd_ipa->curr_cons_bw = next_cons_bw;
3907 hdd_ipa->stats.num_cons_perf_req++;
3908 }
3909
3910 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003911 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003912 hdd_ipa->curr_prod_bw, next_prod_bw);
3913 profile.max_supported_bandwidth_mbps = next_prod_bw;
3914 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3915 &profile);
3916 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003917 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918 return ret;
3919 }
3920 hdd_ipa->curr_prod_bw = next_prod_bw;
3921 hdd_ipa->stats.num_prod_perf_req++;
3922 }
3923
3924 return 0;
3925}
3926
3927/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003928 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3929 * @hdd_ctx: Global HDD context
3930 * @tx_packets: Number of packets transmitted in the last sample period
3931 * @rx_packets: Number of packets received in the last sample period
3932 *
3933 * Return: 0 on success, negative errno on error
3934 */
3935int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3936 uint64_t rx_packets)
3937{
3938 int ret;
3939
3940 cds_ssr_protect(__func__);
3941 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3942 cds_ssr_unprotect(__func__);
3943
3944 return ret;
3945}
3946
3947/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003948 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3949 * @work: struct work_struct
3950 * @work_handler: work_handler
3951 *
3952 * Return: none
3953 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003954static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3955 work_func_t work_handler)
3956{
3957 INIT_WORK(work, work_handler);
3958}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003959
3960/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003961 * hdd_ipa_setup_rm() - Setup IPA resource management
3962 * @hdd_ipa: Global HDD IPA context
3963 *
3964 * Return: 0 on success, negative errno on error
3965 */
3966static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3967{
3968 struct ipa_rm_create_params create_params = { 0 };
3969 int ret;
3970
3971 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3972 return 0;
3973
Rajeev Kumar217f2172016-01-06 18:11:55 -08003974 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3975 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003976 memset(&create_params, 0, sizeof(create_params));
3977 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3978 create_params.reg_params.user_data = hdd_ipa;
3979 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3980 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3981
3982 ret = ipa_rm_create_resource(&create_params);
3983 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303984 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003985 "Create RM resource failed: %d", ret);
3986 goto setup_rm_fail;
3987 }
3988
3989 memset(&create_params, 0, sizeof(create_params));
3990 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3991 create_params.request_resource = hdd_ipa_rm_cons_request;
3992 create_params.release_resource = hdd_ipa_rm_cons_release;
3993 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3994
3995 ret = ipa_rm_create_resource(&create_params);
3996 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303997 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003998 "Create RM CONS resource failed: %d", ret);
3999 goto delete_prod;
4000 }
4001
4002 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
4003 IPA_RM_RESOURCE_APPS_CONS);
4004
4005 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
4006 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
4007 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304008 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004009 ret);
4010 goto timer_init_failed;
4011 }
4012
4013 /* Set the lowest bandwidth to start with */
4014 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
4015
4016 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304017 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004018 "Set perf level failed: %d", ret);
4019 goto set_perf_failed;
4020 }
4021
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304022 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004023 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
4024 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304025 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004026 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
4027 hdd_ipa->wake_lock_released = true;
4028 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
4029
4030 return ret;
4031
4032set_perf_failed:
4033 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4034
4035timer_init_failed:
4036 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4037
4038delete_prod:
4039 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4040
4041setup_rm_fail:
4042 return ret;
4043}
4044
4045/**
4046 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
4047 * @hdd_ipa: Global HDD IPA context
4048 *
4049 * Destroys all resources associated with the IPA resource manager
4050 *
4051 * Return: None
4052 */
4053static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
4054{
4055 int ret;
4056
4057 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4058 return;
4059
4060 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304061 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004062
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004063 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304064 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004065
4066 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4067
4068 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4069 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304070 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071 "RM PROD resource delete failed %d", ret);
4072
4073 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4074 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304075 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004076 "RM CONS resource delete failed %d", ret);
4077}
4078
4079/**
4080 * hdd_ipa_send_skb_to_network() - Send skb to kernel
4081 * @skb: network buffer
4082 * @adapter: network adapter
4083 *
4084 * Called when a network buffer is received which should not be routed
4085 * to the IPA module.
4086 *
4087 * Return: None
4088 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304089static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004090 hdd_adapter_t *adapter)
4091{
4092 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4093 unsigned int cpu_index;
4094
4095 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004096 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004097 adapter);
4098 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004099 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004100 return;
4101 }
4102
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004103 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004104 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004105 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004106 return;
4107 }
4108
4109 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
4110 skb->dev = adapter->dev;
4111 skb->protocol = eth_type_trans(skb, skb->dev);
4112 skb->ip_summed = CHECKSUM_NONE;
4113
4114 cpu_index = wlan_hdd_get_cpu();
4115
4116 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
4117 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
4118 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
4119 else
4120 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
4121
4122 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
4123 adapter->dev->last_rx = jiffies;
4124}
4125
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004126/**
Leo Chang69c39692016-10-12 20:11:12 -07004127 * hdd_ipa_forward() - handle packet forwarding to wlan tx
4128 * @hdd_ipa: pointer to hdd ipa context
4129 * @adapter: network adapter
4130 * @skb: data pointer
4131 *
4132 * if exception packet has set forward bit, copied new packet should be
4133 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
4134 * put into pm queue and tx procedure will be differed
4135 *
4136 * Return: None
4137 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07004138static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
4139 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07004140{
Leo Chang69c39692016-10-12 20:11:12 -07004141 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
4142
Leo Chang69c39692016-10-12 20:11:12 -07004143 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
4144 /* WLAN subsystem is in suspend, put int queue */
4145 if (hdd_ipa->suspended) {
4146 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4147 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4148 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004149 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
4150 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07004151 pm_tx_cb->exception = true;
4152 pm_tx_cb->adapter = adapter;
4153 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004154 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07004155 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4156 hdd_ipa->stats.num_tx_queued++;
4157 } else {
4158 /* Resume, put packet into WLAN TX */
4159 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004160 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07004161 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4162 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08004163 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07004164 } else {
Yun Parkb187d542016-11-14 18:10:04 -08004165 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07004166 hdd_ipa->ipa_tx_forward++;
4167 }
4168 }
4169}
4170
4171/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004172 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
4173 * @hdd_ipa: pointer to HDD IPA struct
4174 * @adapter: hdd adapter pointer
4175 * @desc: Firmware descriptor
4176 * @skb: Data buffer
4177 *
4178 * Return:
4179 * HDD_IPA_FORWARD_PKT_NONE
4180 * HDD_IPA_FORWARD_PKT_DISCARD
4181 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
4182 *
4183 */
4184
4185static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
4186 struct hdd_ipa_priv *hdd_ipa,
4187 hdd_adapter_t *adapter,
4188 uint8_t desc,
4189 qdf_nbuf_t skb)
4190{
4191 int ret = HDD_IPA_FORWARD_PKT_NONE;
4192
4193 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304194 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004195 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
4196 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304197 /* Drop the packet*/
4198 hdd_ipa->stats.num_tx_fwd_err++;
4199 kfree_skb(skb);
4200 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4201 return ret;
4202 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004203 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
4204 "Forward packet to Tx (fw_desc=%d)", desc);
4205 hdd_ipa->ipa_tx_forward++;
4206
4207 if ((desc & FW_RX_DESC_DISCARD_M)) {
4208 hdd_ipa_forward(hdd_ipa, adapter, skb);
4209 hdd_ipa->ipa_rx_internel_drop_count++;
4210 hdd_ipa->ipa_rx_discard++;
4211 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4212 } else {
4213 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004214
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004215 if (cloned_skb)
4216 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
4217 else
4218 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4219 "%s: tx skb alloc failed",
4220 __func__);
4221 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
4222 }
4223 }
4224
4225 return ret;
4226}
4227
4228/**
Yun Park637d6482016-10-05 10:51:33 -07004229 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004230 * @priv: pointer to private data registered with IPA (we register a
4231 * pointer to the global IPA context)
4232 * @evt: the IPA event which triggered the callback
4233 * @data: data associated with the event
4234 *
4235 * Return: None
4236 */
Yun Parkf8d6a122016-10-11 15:49:43 -07004237static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004238 unsigned long data)
4239{
4240 struct hdd_ipa_priv *hdd_ipa = NULL;
4241 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304242 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004243 uint8_t iface_id;
4244 uint8_t session_id;
4245 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004246 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07004247 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004248
4249 hdd_ipa = (struct hdd_ipa_priv *)priv;
4250
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08004251 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
4252 return;
4253
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 switch (evt) {
4255 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05304256 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07004257
4258 /*
4259 * When SSR is going on or driver is unloading,
4260 * just drop the packets.
4261 */
4262 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4263 if (0 != status) {
4264 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4265 "Invalid context: drop packet");
4266 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4267 kfree_skb(skb);
4268 return;
4269 }
4270
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004271 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4272 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004273 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004274 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004275 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4276 session_id, iface_id);
4277 } else {
4278 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4279 }
4280
4281 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304282 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004283 "IPA_RECEIVE: Invalid iface_id: %u",
4284 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004285 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004286 "w2i -- skb",
4287 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004288 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004289 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004290 return;
4291 }
4292
4293 iface_context = &hdd_ipa->iface_context[iface_id];
4294 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08004295 if (!adapter) {
4296 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4297 "IPA_RECEIVE: Adapter is NULL");
4298 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4299 kfree_skb(skb);
4300 return;
4301 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004302
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304303 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004304 "w2i -- skb",
4305 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004306 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4307 hdd_ipa->stats.num_rx_excep++;
4308 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4309 } else {
4310 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4311 }
4312
4313 iface_context->stats.num_rx_ipa_excep++;
4314
4315 /* Disable to forward Intra-BSS Rx packets when
4316 * ap_isolate=1 in hostapd.conf
4317 */
Yun Park046101c2016-09-02 15:32:14 -07004318 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004319 /*
4320 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4321 * all Rx packets to IPA uC, which need to be forwarded
4322 * to other interface.
4323 * And, IPA driver will send back to WLAN host driver
4324 * through exception pipe with fw_desc field set by FW.
4325 * Here we are checking fw_desc field for FORWARD bit
4326 * set, and forward to Tx. Then copy to kernel stack
4327 * only when DISCARD bit is not set.
4328 */
4329 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004330 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4331 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4332 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004333 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004335 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 "Intra-BSS FWD is disabled-skip forward to Tx");
4337 }
4338
4339 hdd_ipa_send_skb_to_network(skb, adapter);
4340 break;
4341
4342 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304343 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344 "w2i cb wrong event: 0x%x", evt);
4345 return;
4346 }
4347}
4348
4349/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004350 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4351 * @priv: pointer to private data registered with IPA (we register a
4352 * pointer to the global IPA context)
4353 * @evt: the IPA event which triggered the callback
4354 * @data: data associated with the event
4355 *
4356 * Return: None
4357 */
4358static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
4359 unsigned long data)
4360{
4361 cds_ssr_protect(__func__);
4362 __hdd_ipa_w2i_cb(priv, evt, data);
4363 cds_ssr_unprotect(__func__);
4364}
4365
4366/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004367 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4368 * @skb: packet buffer which was transmitted
4369 *
4370 * Return: None
4371 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304372void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004373{
4374 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park52b2b992016-09-22 15:49:51 -07004375 struct ipa_rx_data *ipa_tx_desc;
4376 struct hdd_ipa_tx_desc *tx_desc;
4377 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004378
Yun Park52b2b992016-09-22 15:49:51 -07004379 if (!qdf_nbuf_ipa_owned_get(skb)) {
4380 dev_kfree_skb_any(skb);
4381 return;
4382 }
4383
4384 /* Get Tx desc pointer from SKB CB */
4385 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4386 tx_desc = hdd_ipa->tx_desc_list + id;
4387 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4388
4389 /* Return Tx Desc to IPA */
4390 ipa_free_skb(ipa_tx_desc);
4391
4392 /* Return to free tx desc list */
4393 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4394 tx_desc->ipa_tx_desc_ptr = NULL;
4395 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4396 hdd_ipa->stats.num_tx_desc_q_cnt--;
4397 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004398
4399 hdd_ipa->stats.num_tx_comp_cnt++;
4400
4401 atomic_dec(&hdd_ipa->tx_ref_cnt);
4402
4403 hdd_ipa_rm_try_release(hdd_ipa);
4404}
4405
4406/**
4407 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4408 * @iface_context: interface-specific IPA context
4409 * @ipa_tx_desc: packet data descriptor
4410 *
4411 * Return: None
4412 */
4413static void hdd_ipa_send_pkt_to_tl(
4414 struct hdd_ipa_iface_context *iface_context,
4415 struct ipa_rx_data *ipa_tx_desc)
4416{
4417 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004418 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304419 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004420 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004421
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304422 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423 adapter = iface_context->adapter;
4424 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304425 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004426 ipa_free_skb(ipa_tx_desc);
4427 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304428 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004429 hdd_ipa_rm_try_release(hdd_ipa);
4430 return;
4431 }
4432
4433 /*
4434 * During CAC period, data packets shouldn't be sent over the air so
4435 * drop all the packets here
4436 */
4437 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4438 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304439 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004440 iface_context->stats.num_tx_cac_drop++;
4441 hdd_ipa_rm_try_release(hdd_ipa);
4442 return;
4443 }
4444
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004445 ++adapter->stats.tx_packets;
4446
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304447 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004448
4449 skb = ipa_tx_desc->skb;
4450
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304451 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004452
4453 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304454 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004455 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304456 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004457 ipa_tx_desc->dma_addr
4458 + HDD_IPA_WLAN_FRAG_HEADER
4459 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004460 ipa_tx_desc->skb->len -=
4461 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4462 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304463 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004464
Yun Park52b2b992016-09-22 15:49:51 -07004465 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4466 /* get free Tx desc and assign ipa_tx_desc pointer */
4467 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4468 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4469 struct hdd_ipa_tx_desc, link);
4470 list_del(&tx_desc->link);
4471 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4472 hdd_ipa->stats.num_tx_desc_q_cnt++;
4473 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4474 /* Store Tx Desc index into SKB CB */
4475 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4476 } else {
4477 hdd_ipa->stats.num_tx_desc_error++;
4478 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4479 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "No free Tx desc!");
4480 ipa_free_skb(ipa_tx_desc);
4481 hdd_ipa_rm_try_release(hdd_ipa);
4482 return;
4483 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484
4485 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
4486
Leo Changfdb45c32016-10-28 11:09:23 -07004487 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004488 (struct cdp_vdev *)iface_context->tl_context,
4489 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004490 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304491 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004492 ipa_free_skb(ipa_tx_desc);
4493 iface_context->stats.num_tx_err++;
4494 hdd_ipa_rm_try_release(hdd_ipa);
4495 return;
4496 }
4497
4498 atomic_inc(&hdd_ipa->tx_ref_cnt);
4499
4500 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004501}
4502
4503/**
Leo Chang11545d62016-10-17 14:53:50 -07004504 * hdd_ipa_is_present() - get IPA hw status
4505 * @hdd_ctx: pointer to hdd context
4506 *
4507 * ipa_uc_reg_rdyCB is not directly designed to check
4508 * ipa hw status. This is an undocumented function which
4509 * has confirmed with IPA team.
4510 *
4511 * Return: true - ipa hw present
4512 * false - ipa hw not present
4513 */
4514bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
4515{
4516 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004517 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004518 return true;
4519 else
4520 return false;
4521}
4522
4523/**
Leo Chang69c39692016-10-12 20:11:12 -07004524 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004525 * @work: pointer to the scheduled work
4526 *
4527 * Called during PM resume to send packets to TL which were queued
4528 * while host was in the process of suspending.
4529 *
4530 * Return: None
4531 */
Leo Chang69c39692016-10-12 20:11:12 -07004532static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004533{
4534 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4535 struct hdd_ipa_priv,
4536 pm_work);
4537 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304538 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004539 uint32_t dequeued = 0;
4540
Leo Chang69c39692016-10-12 20:11:12 -07004541 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4542 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304543 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304544 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4545 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304546 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004547
4548 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004549 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004550 if (pm_tx_cb->exception) {
4551 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4552 "FLUSH EXCEPTION");
4553 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
4554 } else {
4555 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004556 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004557 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304558 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004559 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304560 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004561 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4562 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563
4564 hdd_ipa->stats.num_tx_dequeued += dequeued;
4565 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4566 hdd_ipa->stats.num_max_pm_queue = dequeued;
4567}
4568
4569/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004570 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004571 * @priv: pointer to private data registered with IPA (we register a
4572 * pointer to the interface-specific IPA context)
4573 * @evt: the IPA event which triggered the callback
4574 * @data: data associated with the event
4575 *
4576 * Return: None
4577 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004578static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004579 unsigned long data)
4580{
4581 struct hdd_ipa_priv *hdd_ipa = NULL;
4582 struct ipa_rx_data *ipa_tx_desc;
4583 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304584 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004585 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304586 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004587
Mukul Sharma81661ae2015-10-30 20:26:02 +05304588 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004589 ipa_tx_desc = (struct ipa_rx_data *)data;
4590 hdd_ipa = iface_context->hdd_ipa;
4591
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004592 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004593 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4594 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004595 iface_context->stats.num_tx_drop++;
4596 return;
4597 }
4598
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004599 /*
4600 * When SSR is going on or driver is unloading, just drop the packets.
4601 * During SSR, there is no use in queueing the packets as STA has to
4602 * connect back any way
4603 */
4604 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304605 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004606 ipa_free_skb(ipa_tx_desc);
4607 iface_context->stats.num_tx_drop++;
4608 return;
4609 }
4610
4611 skb = ipa_tx_desc->skb;
4612
Yun Parkb187d542016-11-14 18:10:04 -08004613 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4614 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615
4616 /*
4617 * If PROD resource is not requested here then there may be cases where
4618 * IPA hardware may be clocked down because of not having proper
4619 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4620 * workaround to request PROD resource while data is going over CONS
4621 * pipe to prevent the IPA hardware clockdown.
4622 */
4623 hdd_ipa_rm_request(hdd_ipa);
4624
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304625 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004626 /*
4627 * If host is still suspended then queue the packets and these will be
4628 * drained later when resume completes. When packet is arrived here and
4629 * host is suspended, this means that there is already resume is in
4630 * progress.
4631 */
4632 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304633 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4635 pm_tx_cb->iface_context = iface_context;
4636 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304637 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 hdd_ipa->stats.num_tx_queued++;
4639
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304640 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004641 return;
4642 }
4643
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304644 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004645
4646 /*
4647 * If we are here means, host is not suspended, wait for the work queue
4648 * to finish.
4649 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004650 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004651
4652 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4653}
4654
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004655/*
4656 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4657 * @priv: pointer to private data registered with IPA (we register a
4658 * pointer to the interface-specific IPA context)
4659 * @evt: the IPA event which triggered the callback
4660 * @data: data associated with the event
4661 *
4662 * Return: None
4663 */
4664static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
4665 unsigned long data)
4666{
4667 cds_ssr_protect(__func__);
4668 __hdd_ipa_i2w_cb(priv, evt, data);
4669 cds_ssr_unprotect(__func__);
4670}
4671
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004672/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004673 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004674 * @hdd_ctx: Global HDD context
4675 *
4676 * Return: 0 on success, negativer errno on error
4677 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004678static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004679{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004680 struct hdd_ipa_priv *hdd_ipa;
4681
4682 if (wlan_hdd_validate_context(hdd_ctx))
4683 return 0;
4684
4685 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004686
4687 if (!hdd_ipa_is_enabled(hdd_ctx))
4688 return 0;
4689
4690 /*
4691 * Check if IPA is ready for suspend, If we are here means, there is
4692 * high chance that suspend would go through but just to avoid any race
4693 * condition after suspend started, these checks are conducted before
4694 * allowing to suspend.
4695 */
4696 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4697 return -EAGAIN;
4698
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304699 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004700
4701 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304702 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004703 return -EAGAIN;
4704 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304705 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004706
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304707 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004708 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304709 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004710
4711 return 0;
4712}
4713
4714/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004715 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4716 * @hdd_ctx: Global HDD context
4717 *
4718 * Return: 0 on success, negativer errno on error
4719 */
4720int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4721{
4722 int ret;
4723
4724 cds_ssr_protect(__func__);
4725 ret = __hdd_ipa_suspend(hdd_ctx);
4726 cds_ssr_unprotect(__func__);
4727
4728 return ret;
4729}
4730
4731/**
4732 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004733 * hdd_ctx: Global HDD context
4734 *
4735 * Return: 0 on success, negative errno on error
4736 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004737static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004738{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004739 struct hdd_ipa_priv *hdd_ipa;
4740
4741 if (wlan_hdd_validate_context(hdd_ctx))
4742 return 0;
4743
4744 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004745
4746 if (!hdd_ipa_is_enabled(hdd_ctx))
4747 return 0;
4748
4749 schedule_work(&hdd_ipa->pm_work);
4750
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304751 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004752 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304753 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004754
4755 return 0;
4756}
4757
4758/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004759 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4760 * hdd_ctx: Global HDD context
4761 *
4762 * Return: 0 on success, negative errno on error
4763 */
4764int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4765{
4766 int ret;
4767
4768 cds_ssr_protect(__func__);
4769 ret = __hdd_ipa_resume(hdd_ctx);
4770 cds_ssr_unprotect(__func__);
4771
4772 return ret;
4773}
4774
4775/**
Yun Park52b2b992016-09-22 15:49:51 -07004776 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
4777 * @hdd_ipa: Global HDD IPA context
4778 *
4779 * Return: 0 on success, negative errno on error
4780 */
4781static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
4782{
4783 int i;
4784 uint32_t max_desc_cnt;
4785 struct hdd_ipa_tx_desc *tmp_desc;
4786
4787 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
4788
4789 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
4790
4791 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc)*max_desc_cnt);
4792
4793 if (!tmp_desc) {
4794 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4795 "Free Tx descriptor allocation failed");
4796 return -ENOMEM;
4797 }
4798
4799 hdd_ipa->tx_desc_list = tmp_desc;
4800
4801 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4802 for (i = 0; i < max_desc_cnt; i++) {
4803 tmp_desc->id = i;
4804 tmp_desc->ipa_tx_desc_ptr = NULL;
4805 list_add_tail(&tmp_desc->link,
4806 &hdd_ipa->free_tx_desc_head);
4807 tmp_desc++;
4808 }
4809
4810 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4811 hdd_ipa->stats.num_tx_desc_error = 0;
4812
4813 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4814
4815 return 0;
4816}
4817
4818/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004819 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4820 * @hdd_ipa: Global HDD IPA context
4821 *
4822 * Return: 0 on success, negative errno on error
4823 */
4824static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4825{
4826 int i, ret = 0;
4827 struct ipa_sys_connect_params *ipa;
4828 uint32_t desc_fifo_sz;
4829
4830 /* The maximum number of descriptors that can be provided to a BAM at
4831 * once is one less than the total number of descriptors that the buffer
4832 * can contain.
4833 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4834 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4835 * be provided at once.
4836 * Because of above requirement, one extra descriptor will be added to
4837 * make sure hardware always has one descriptor.
4838 */
4839 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4840 + sizeof(struct sps_iovec);
4841
4842 /*setup TX pipes */
4843 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4844 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4845
4846 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4847 ipa->desc_fifo_sz = desc_fifo_sz;
4848 ipa->priv = &hdd_ipa->iface_context[i];
4849 ipa->notify = hdd_ipa_i2w_cb;
4850
4851 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4852 ipa->ipa_ep_cfg.hdr.hdr_len =
4853 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4854 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4855 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4856 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4857 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4858 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4859 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4860 } else {
4861 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4862 }
4863 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4864
4865 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4866 ipa->keep_ipa_awake = 1;
4867
4868 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4869 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004870 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4871 "Failed for pipe %d ret: %d", i, ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004872 goto setup_sys_pipe_fail;
4873 }
4874 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4875 }
4876
4877 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4878 /*
4879 * Hard code it here, this can be extended if in case
4880 * PROD pipe is also per interface.
4881 * Right now there is no advantage of doing this.
4882 */
4883 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4884
4885 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4886
4887 ipa->client = hdd_ipa->prod_client;
4888
4889 ipa->desc_fifo_sz = desc_fifo_sz;
4890 ipa->priv = hdd_ipa;
4891 ipa->notify = hdd_ipa_w2i_cb;
4892
4893 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4894 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4895 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4896 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4897
4898 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4899 ipa->keep_ipa_awake = 1;
4900
4901 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4902 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304903 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004904 "Failed for RX pipe: %d", ret);
4905 goto setup_sys_pipe_fail;
4906 }
4907 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4908 }
4909
Yun Park52b2b992016-09-22 15:49:51 -07004910 /* Allocate free Tx desc list */
4911 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
4912 if (ret)
4913 goto setup_sys_pipe_fail;
4914
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004915 return ret;
4916
4917setup_sys_pipe_fail:
4918
4919 while (--i >= 0) {
4920 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304921 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004922 sizeof(struct hdd_ipa_sys_pipe));
4923 }
4924
4925 return ret;
4926}
4927
4928/**
4929 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4930 * @hdd_ipa: Global HDD IPA context
4931 *
4932 * Return: None
4933 */
4934static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4935{
4936 int ret = 0, i;
Yun Park52b2b992016-09-22 15:49:51 -07004937 uint32_t max_desc_cnt;
4938 struct hdd_ipa_tx_desc *tmp_desc;
4939 struct ipa_rx_data *ipa_tx_desc;
4940
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004941 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4942 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4943 ret =
4944 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4945 conn_hdl);
4946 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304947 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004948 ret);
4949
4950 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4951 }
4952 }
Yun Park52b2b992016-09-22 15:49:51 -07004953
4954 if (hdd_ipa->tx_desc_list) {
4955 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
4956
4957 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4958 for (i = 0; i < max_desc_cnt; i++) {
4959 tmp_desc = hdd_ipa->tx_desc_list + i;
4960 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
4961 if (ipa_tx_desc)
4962 ipa_free_skb(ipa_tx_desc);
4963 }
4964 tmp_desc = hdd_ipa->tx_desc_list;
4965 hdd_ipa->tx_desc_list = NULL;
4966 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4967 hdd_ipa->stats.num_tx_desc_error = 0;
4968 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4969 qdf_mem_free(tmp_desc);
4970 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004971}
4972
4973/**
4974 * hdd_ipa_register_interface() - register IPA interface
4975 * @hdd_ipa: Global IPA context
4976 * @iface_context: Per-interface IPA context
4977 *
4978 * Return: 0 on success, negative errno on error
4979 */
4980static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
4981 struct hdd_ipa_iface_context
4982 *iface_context)
4983{
4984 struct ipa_tx_intf tx_intf;
4985 struct ipa_rx_intf rx_intf;
4986 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
4987 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
4988 char *ifname = iface_context->adapter->dev->name;
4989
4990 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
4991 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
4992
4993 int num_prop = 1;
4994 int ret = 0;
4995
4996 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
4997 num_prop++;
4998
4999 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
5000 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305001 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005002 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305003 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005004 goto register_interface_fail;
5005 }
5006
5007 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
5008 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305009 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005010 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305011 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005012 goto register_interface_fail;
5013 }
5014
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305015 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
5016 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005017
5018 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
5019 ifname, HDD_IPA_IPV4_NAME_EXT);
5020 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
5021 ifname, HDD_IPA_IPV6_NAME_EXT);
5022
5023 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
5024 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
5025 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5026 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
5027
5028 /*
5029 * Interface ID is 3rd byte in the CLD header. Add the meta data and
5030 * mask to identify the interface in IPA hardware
5031 */
5032 rx_prop[IPA_IP_v4].attrib.meta_data =
5033 htonl(iface_context->adapter->sessionId << 16);
5034 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
5035
5036 rx_intf.num_props++;
5037 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5038 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
5039 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
5040 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5041 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
5042 rx_prop[IPA_IP_v4].attrib.meta_data =
5043 htonl(iface_context->adapter->sessionId << 16);
5044 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
5045
5046 rx_intf.num_props++;
5047 }
5048
5049 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
5050 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5051 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
5052 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
5053 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
5054 IPA_RESOURCE_NAME_MAX);
5055 tx_intf.num_props++;
5056
5057 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5058 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
5059 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5060 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
5061 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
5062 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
5063 IPA_RESOURCE_NAME_MAX);
5064 tx_intf.num_props++;
5065 }
5066
5067 tx_intf.prop = tx_prop;
5068 rx_intf.prop = rx_prop;
5069
5070 /* Call the ipa api to register interface */
5071 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
5072
Yun Park52b2b992016-09-22 15:49:51 -07005073 /* Register IPA Tx desc free callback */
5074 qdf_nbuf_reg_free_cb(hdd_ipa_nbuf_cb);
5075
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005076register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305077 qdf_mem_free(tx_prop);
5078 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005079 return ret;
5080}
5081
5082/**
5083 * hdd_remove_ipa_header() - Remove a specific header from IPA
5084 * @name: Name of the header to be removed
5085 *
5086 * Return: None
5087 */
5088static void hdd_ipa_remove_header(char *name)
5089{
5090 struct ipa_ioc_get_hdr hdrlookup;
5091 int ret = 0, len;
5092 struct ipa_ioc_del_hdr *ipa_hdr;
5093
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305094 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005095 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
5096 ret = ipa_get_hdr(&hdrlookup);
5097 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005098 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005099 name, ret);
5100 return;
5101 }
5102
Srinivas Girigowda97852372017-03-06 16:52:59 -08005103 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005104 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305105 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005106 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305107 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005108 return;
5109 }
5110 ipa_hdr->num_hdls = 1;
5111 ipa_hdr->commit = 0;
5112 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
5113 ipa_hdr->hdl[0].status = -1;
5114 ret = ipa_del_hdr(ipa_hdr);
5115 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305116 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005117 ret);
5118
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305119 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005120}
5121
5122/**
Yun Parkb187d542016-11-14 18:10:04 -08005123 * wlan_ipa_add_hdr() - Add IPA Tx header
5124 * @ipa_hdr: pointer to IPA header addition parameters
5125 *
5126 * Call IPA API to add IPA Tx header descriptor
5127 * and dump Tx header struct
5128 *
5129 * Return: 0 for success, non-zero for failure
5130 */
5131static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
5132{
5133 int ret;
5134
Srinivas Girigowda97852372017-03-06 16:52:59 -08005135 hdd_debug("==== IPA Tx Header ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08005136 "name: %s\n"
5137 "hdr_len: %d\n"
5138 "type: %d\n"
5139 "is_partial: %d\n"
5140 "hdr_hdl: 0x%x\n"
5141 "status: %d\n"
5142 "is_eth2_ofst_valid: %d\n"
5143 "eth2_ofst: %d\n",
5144 ipa_hdr->hdr[0].name,
5145 ipa_hdr->hdr[0].hdr_len,
5146 ipa_hdr->hdr[0].type,
5147 ipa_hdr->hdr[0].is_partial,
5148 ipa_hdr->hdr[0].hdr_hdl,
5149 ipa_hdr->hdr[0].status,
5150 ipa_hdr->hdr[0].is_eth2_ofst_valid,
5151 ipa_hdr->hdr[0].eth2_ofst);
5152
Srinivas Girigowdac06543c2017-03-09 15:10:03 -08005153 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, "hdr:",
Yun Parkb187d542016-11-14 18:10:04 -08005154 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
5155
5156 ret = ipa_add_hdr(ipa_hdr);
5157 return ret;
5158}
5159
5160/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005161 * hdd_ipa_add_header_info() - Add IPA header for a given interface
5162 * @hdd_ipa: Global HDD IPA context
5163 * @iface_context: Interface-specific HDD IPA context
5164 * @mac_addr: Interface MAC address
5165 *
5166 * Return: 0 on success, negativer errno value on error
5167 */
5168static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
5169 struct hdd_ipa_iface_context *iface_context,
5170 uint8_t *mac_addr)
5171{
5172 hdd_adapter_t *adapter = iface_context->adapter;
5173 char *ifname;
5174 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
5175 int ret = -EINVAL;
5176 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
5177 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
5178
5179 ifname = adapter->dev->name;
5180
Srinivas Girigowda97852372017-03-06 16:52:59 -08005181 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005182 ifname, mac_addr);
5183
5184 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305185 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005186 + sizeof(struct ipa_hdr_add));
5187 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305188 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005189 "%s: ipa_hdr allocation failed", ifname);
5190 ret = -ENOMEM;
5191 goto end;
5192 }
5193
5194 ipa_hdr->commit = 0;
5195 ipa_hdr->num_hdrs = 1;
5196
5197 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5198 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
5199 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
5200 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
5201 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305202 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005203 "ifname=%s, vdev_id=%d",
5204 ifname, uc_tx_hdr->ipa_hd.vdev_id);
5205 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5206 ifname, HDD_IPA_IPV4_NAME_EXT);
5207 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
5208 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
5209 ipa_hdr->hdr[0].is_partial = 1;
5210 ipa_hdr->hdr[0].hdr_hdl = 0;
5211 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
5212 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5213
Yun Parkb187d542016-11-14 18:10:04 -08005214 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005215 } else {
5216 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
5217
5218 /* Set the Source MAC */
5219 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
5220 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
5221
5222 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5223 ifname, HDD_IPA_IPV4_NAME_EXT);
5224 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
5225 ipa_hdr->hdr[0].is_partial = 1;
5226 ipa_hdr->hdr[0].hdr_hdl = 0;
5227 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
5228 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5229
5230 /* Set the type to IPV4 in the header */
5231 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
5232
5233 ret = ipa_add_hdr(ipa_hdr);
5234 }
5235 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305236 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005237 ifname, ret);
5238 goto end;
5239 }
5240
Srinivas Girigowda97852372017-03-06 16:52:59 -08005241 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005242 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
5243
5244 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5245 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5246 ifname, HDD_IPA_IPV6_NAME_EXT);
5247
5248 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5249 uc_tx_hdr =
5250 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
5251 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08005252 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005253 } else {
5254 /* Set the type to IPV6 in the header */
5255 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
5256 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08005257 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005258 }
5259
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005260 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305261 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005262 "%s: IPv6 add hdr failed: %d", ifname, ret);
5263 goto clean_ipv4_hdr;
5264 }
5265
Srinivas Girigowda97852372017-03-06 16:52:59 -08005266 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005267 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
5268 }
5269
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305270 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005271
5272 return ret;
5273
5274clean_ipv4_hdr:
5275 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5276 ifname, HDD_IPA_IPV4_NAME_EXT);
5277 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
5278end:
5279 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305280 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005281
5282 return ret;
5283}
5284
5285/**
5286 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
5287 * @adapter: Adapter upon which IPA was previously configured
5288 *
5289 * Return: None
5290 */
5291static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
5292{
5293 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5294 int ret;
5295 char name_ipa[IPA_RESOURCE_NAME_MAX];
5296
5297 /* Remove the headers */
5298 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
5299 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
5300 hdd_ipa_remove_header(name_ipa);
5301
5302 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5303 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
5304 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
5305 hdd_ipa_remove_header(name_ipa);
5306 }
5307 /* unregister the interface with IPA */
5308 ret = ipa_deregister_intf(adapter->dev->name);
5309 if (ret)
Srinivas Girigowda97852372017-03-06 16:52:59 -08005310 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005311 "%s: ipa_deregister_intf fail: %d",
5312 adapter->dev->name, ret);
5313}
5314
5315/**
5316 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
5317 * @iface_context: interface-specific IPA context
5318 *
5319 * Return: None
5320 */
5321static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
5322{
5323 if (iface_context == NULL)
5324 return;
5325
5326 hdd_ipa_clean_hdr(iface_context->adapter);
5327
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305328 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005329 iface_context->adapter->ipa_context = NULL;
5330 iface_context->adapter = NULL;
5331 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305332 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005333 iface_context->ifa_address = 0;
5334 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305335 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005336 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05305337 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005338 }
5339 iface_context->hdd_ipa->num_iface--;
5340}
5341
5342/**
5343 * hdd_ipa_setup_iface() - Setup IPA on a given interface
5344 * @hdd_ipa: HDD IPA global context
5345 * @adapter: Interface upon which IPA is being setup
5346 * @sta_id: Station ID of the API instance
5347 *
5348 * Return: 0 on success, negative errno value on error
5349 */
5350static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
5351 hdd_adapter_t *adapter, uint8_t sta_id)
5352{
5353 struct hdd_ipa_iface_context *iface_context = NULL;
5354 void *tl_context = NULL;
5355 int i, ret = 0;
5356
5357 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
5358 * channel change indication. Since these indications are sent by lower
5359 * layer as SAP updates and IPA doesn't have to do anything for these
5360 * updates so ignoring!
5361 */
Krunal Sonibe766b02016-03-10 13:00:44 -08005362 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005363 return 0;
5364
5365 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5366 if (hdd_ipa->iface_context[i].adapter == NULL) {
5367 iface_context = &(hdd_ipa->iface_context[i]);
5368 break;
5369 }
5370 }
5371
5372 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305373 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005374 "All the IPA interfaces are in use");
5375 ret = -ENOMEM;
5376 goto end;
5377 }
5378
5379 adapter->ipa_context = iface_context;
5380 iface_context->adapter = adapter;
5381 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08005382 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07005383 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005384 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305385 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005386 "Not able to get TL context sta_id: %d", sta_id);
5387 ret = -EINVAL;
5388 goto end;
5389 }
5390
5391 iface_context->tl_context = tl_context;
5392
5393 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
5394 adapter->dev->dev_addr);
5395
5396 if (ret)
5397 goto end;
5398
5399 /* Configure the TX and RX pipes filter rules */
5400 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
5401 if (ret)
5402 goto cleanup_header;
5403
5404 hdd_ipa->num_iface++;
5405 return ret;
5406
5407cleanup_header:
5408
5409 hdd_ipa_clean_hdr(adapter);
5410end:
5411 if (iface_context)
5412 hdd_ipa_cleanup_iface(iface_context);
5413 return ret;
5414}
5415
Yun Parka27049a2016-10-11 12:30:49 -07005416#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005417/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005418 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005419 * @mcc_mode: 0=MCC/1=SCC
5420 *
5421 * Return: 0 on success, negative errno value on error
5422 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005423static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005424{
5425 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305426 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005427 hdd_adapter_t *pAdapter;
5428 struct ipa_msg_meta meta;
5429 struct ipa_wlan_msg *msg;
5430 int ret;
5431
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005432 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005433 return -EINVAL;
5434
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005435 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
5436 return -EINVAL;
5437
5438 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005439 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005440 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305441 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005442 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08005443 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005444 pAdapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005445 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005446 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005447 hdd_deinit_tx_rx(pAdapter);
5448 }
5449 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005450 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005451 adapter_node = next;
5452 }
5453 }
5454
5455 /* Send SCC/MCC Switching event to IPA */
5456 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305457 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005458 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005459 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005460 return -ENOMEM;
5461 }
5462
5463 meta.msg_type = mcc_mode ?
5464 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Srinivas Girigowda97852372017-03-06 16:52:59 -08005465 hdd_debug("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005466
5467 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5468
5469 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005470 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005471 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305472 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005473 }
5474
5475 return ret;
5476}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005477
5478/**
5479 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5480 * @mcc_mode: 0=MCC/1=SCC
5481 *
5482 * Return: 0 on success, negative errno value on error
5483 */
5484int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
5485{
5486 int ret;
5487
5488 cds_ssr_protect(__func__);
5489 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5490 cds_ssr_unprotect(__func__);
5491
5492 return ret;
5493}
Yun Parka27049a2016-10-11 12:30:49 -07005494#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005495
5496/**
5497 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
5498 * @event: IPA WLAN event to be converted to a string
5499 *
5500 * Return: ASCII string representing the IPA WLAN event
5501 */
5502static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
5503{
5504 switch (event) {
5505 case WLAN_CLIENT_CONNECT:
5506 return "WLAN_CLIENT_CONNECT";
5507 case WLAN_CLIENT_DISCONNECT:
5508 return "WLAN_CLIENT_DISCONNECT";
5509 case WLAN_CLIENT_POWER_SAVE_MODE:
5510 return "WLAN_CLIENT_POWER_SAVE_MODE";
5511 case WLAN_CLIENT_NORMAL_MODE:
5512 return "WLAN_CLIENT_NORMAL_MODE";
5513 case SW_ROUTING_ENABLE:
5514 return "SW_ROUTING_ENABLE";
5515 case SW_ROUTING_DISABLE:
5516 return "SW_ROUTING_DISABLE";
5517 case WLAN_AP_CONNECT:
5518 return "WLAN_AP_CONNECT";
5519 case WLAN_AP_DISCONNECT:
5520 return "WLAN_AP_DISCONNECT";
5521 case WLAN_STA_CONNECT:
5522 return "WLAN_STA_CONNECT";
5523 case WLAN_STA_DISCONNECT:
5524 return "WLAN_STA_DISCONNECT";
5525 case WLAN_CLIENT_CONNECT_EX:
5526 return "WLAN_CLIENT_CONNECT_EX";
5527
5528 case IPA_WLAN_EVENT_MAX:
5529 default:
5530 return "UNKNOWN";
5531 }
5532}
5533
5534/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005535 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5536 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5537 *
5538 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
5539 */
5540static enum ipa_wlan_event
5541hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5542{
5543 enum ipa_wlan_event ipa_event;
5544
5545 switch (hdd_ipa_event_type) {
5546 case HDD_IPA_CLIENT_CONNECT:
5547 ipa_event = WLAN_CLIENT_CONNECT;
5548 break;
5549 case HDD_IPA_CLIENT_DISCONNECT:
5550 ipa_event = WLAN_CLIENT_DISCONNECT;
5551 break;
5552 case HDD_IPA_AP_CONNECT:
5553 ipa_event = WLAN_AP_CONNECT;
5554 break;
5555 case HDD_IPA_AP_DISCONNECT:
5556 ipa_event = WLAN_AP_DISCONNECT;
5557 break;
5558 case HDD_IPA_STA_CONNECT:
5559 ipa_event = WLAN_STA_CONNECT;
5560 break;
5561 case HDD_IPA_STA_DISCONNECT:
5562 ipa_event = WLAN_STA_DISCONNECT;
5563 break;
5564 case HDD_IPA_CLIENT_CONNECT_EX:
5565 ipa_event = WLAN_CLIENT_CONNECT_EX;
5566 break;
5567 case HDD_IPA_WLAN_EVENT_MAX:
5568 default:
5569 ipa_event = IPA_WLAN_EVENT_MAX;
5570 break;
5571 }
5572 return ipa_event;
5573
5574}
5575
5576/**
5577 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005578 * @adapter: adapter upon which the event was received
5579 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005580 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005581 * @mac_address: MAC address associated with the event
5582 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005583 * This function is meant to be called from within wlan_hdd_ipa.c
5584 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005585 * Return: 0 on success, negative errno value on error
5586 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07005587static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005588 enum ipa_wlan_event type, uint8_t *mac_addr)
5589{
5590 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5591 struct ipa_msg_meta meta;
5592 struct ipa_wlan_msg *msg;
5593 struct ipa_wlan_msg_ex *msg_ex = NULL;
5594 int ret;
5595
Srinivas Girigowda97852372017-03-06 16:52:59 -08005596 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005597 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5598 mac_addr, sta_id);
5599
5600 if (type >= IPA_WLAN_EVENT_MAX)
5601 return -EINVAL;
5602
5603 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5604 return -EINVAL;
5605
5606 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305607 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005608 return -EINVAL;
5609 }
5610
5611 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5612 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005613 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005614 return 0;
5615 }
5616
5617 /*
5618 * During IPA UC resource loading/unloading new events can be issued.
5619 * Store the events separately and handle them later.
5620 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005621 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5622 if (hdd_ipa->resource_loading) {
5623 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005624 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005625
Yun Park64c405e2017-01-10 22:35:51 -08005626 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5627 "IPA resource load in progress");
Yun Park7c4f31b2016-11-30 10:09:21 -08005628
Yun Park64c405e2017-01-10 22:35:51 -08005629 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005630
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005631 pending_event_count =
5632 qdf_list_size(&hdd_ipa->pending_event);
5633 if (pending_event_count >=
5634 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005635 hdd_debug("Reached max pending event count");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005636 qdf_list_remove_front(&hdd_ipa->pending_event,
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005637 (qdf_list_node_t **)&pending_event);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005638 } else {
5639 pending_event =
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005640 qdf_mem_malloc(sizeof(*pending_event));
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005641 }
5642
5643 if (!pending_event) {
Yun Park64c405e2017-01-10 22:35:51 -08005644 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park7c4f31b2016-11-30 10:09:21 -08005645 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5646 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005647 return -ENOMEM;
5648 }
5649
5650 pending_event->adapter = adapter;
5651 pending_event->sta_id = sta_id;
5652 pending_event->type = type;
5653 qdf_mem_copy(pending_event->mac_addr,
5654 mac_addr,
5655 QDF_MAC_ADDR_SIZE);
5656 qdf_list_insert_back(&hdd_ipa->pending_event,
5657 &pending_event->node);
5658
Yun Park64c405e2017-01-10 22:35:51 -08005659 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005660 return 0;
5661 } else if (hdd_ipa->resource_unloading) {
Yun Park64c405e2017-01-10 22:35:51 -08005662 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5663 "IPA resource unload in progress");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005664 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005665 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005666 }
5667
5668 hdd_ipa->stats.event[type]++;
5669
Leo Chang3bc8fed2015-11-13 10:59:47 -08005670 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005671 switch (type) {
5672 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005673 qdf_mutex_acquire(&hdd_ipa->event_lock);
5674
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005675 /* STA already connected and without disconnect, connect again
5676 * This is Roaming scenario
5677 */
5678 if (hdd_ipa->sta_connected)
5679 hdd_ipa_cleanup_iface(adapter->ipa_context);
5680
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005681 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5682 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305683 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005684 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005685 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005686
Yun Park8f289c82016-10-18 16:38:21 -07005687 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5688 (hdd_ipa->sap_num_connected_sta > 0) &&
5689 !hdd_ipa->sta_connected) {
5690 qdf_mutex_release(&hdd_ipa->event_lock);
5691 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005692 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005693 qdf_mutex_acquire(&hdd_ipa->event_lock);
5694 }
5695
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005696 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005697 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005698 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005699
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005700 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005701
5702 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005703 break;
5704
5705 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005706 qdf_mutex_acquire(&hdd_ipa->event_lock);
5707
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005708 /* For DFS channel we get two start_bss event (before and after
5709 * CAC). Also when ACS range includes both DFS and non DFS
5710 * channels, we could possibly change channel many times due to
5711 * RADAR detection and chosen channel may not be a DFS channels.
5712 * So dont return error here. Just discard the event.
5713 */
Yun Park8f289c82016-10-18 16:38:21 -07005714 if (adapter->ipa_context) {
5715 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005716 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005717 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005718
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005719 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5720 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005721 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005722 hdd_err("%s: Evt: %d, Interface setup failed",
5723 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005724 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005725 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005726
Yun Park8f289c82016-10-18 16:38:21 -07005727 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5728 qdf_mutex_release(&hdd_ipa->event_lock);
5729 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005730 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005731 qdf_mutex_acquire(&hdd_ipa->event_lock);
5732 }
5733
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005734 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005735 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005736 (adapter->ipa_context))->iface_id;
5737
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305738 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005739 break;
5740
5741 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305742 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005743
5744 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005745 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005746 hdd_err("%s: Evt: %d, STA already disconnected",
5747 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005748 return -EINVAL;
5749 }
Yun Parka37592b2016-06-11 17:10:28 -07005750
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005751 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005752
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005753 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005754 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005755 msg_ex->name);
5756 } else {
5757 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005758 if (!hdd_ipa->num_iface &&
5759 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305760 hdd_ipa->activated_fw_pipe) &&
5761 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005762 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005763 }
5764
Yun Park74127cf2016-09-18 11:22:41 -07005765 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5766 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005767 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005768 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005769 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005770 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005771 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5772 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005773 }
5774
Yun Park8f289c82016-10-18 16:38:21 -07005775 hdd_ipa_cleanup_iface(adapter->ipa_context);
5776
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305777 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005778 break;
5779
5780 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005781 qdf_mutex_acquire(&hdd_ipa->event_lock);
5782
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005783 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005784 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005785 hdd_err("%s: Evt: %d, SAP already disconnected",
5786 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005787 return -EINVAL;
5788 }
5789
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005790 if ((!hdd_ipa->num_iface) &&
5791 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305792 hdd_ipa->activated_fw_pipe) &&
5793 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005794 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005795 /*
5796 * We disable WDI pipes directly here since
5797 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5798 * processed when unloading WLAN driver is in
5799 * progress
5800 */
5801 hdd_ipa_uc_disable_pipes(hdd_ipa);
5802 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305803 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005804 "NO INTF left but still pipe clean up");
5805 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5806 }
5807 }
5808
5809 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005810 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005811 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005812 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005813 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005814 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5815 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005816 }
Yun Parka37592b2016-06-11 17:10:28 -07005817
Yun Park8f289c82016-10-18 16:38:21 -07005818 hdd_ipa_cleanup_iface(adapter->ipa_context);
5819
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305820 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005821 break;
5822
5823 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005824 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005825 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005826 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305827 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005828 return 0;
5829 }
5830
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305831 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005832 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5833 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005834 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305835 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005836 "%s: STA ID %d found, not valid",
5837 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005838 return 0;
5839 }
Yun Park312f71a2015-12-08 10:22:42 -08005840
5841 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005842 if (hdd_ipa->sap_num_connected_sta == 0 &&
5843 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005844 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005845 hdd_ipa->sta_connected) {
5846 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005847 hdd_ipa_uc_offload_enable_disable(
5848 hdd_get_adapter(hdd_ipa->hdd_ctx,
5849 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005850 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005851 qdf_mutex_acquire(&hdd_ipa->event_lock);
5852 }
Yun Parka37592b2016-06-11 17:10:28 -07005853
Yun Park312f71a2015-12-08 10:22:42 -08005854 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5855 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305856 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005857 "%s: handle 1st con ret %d",
5858 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005859
5860 if (hdd_ipa_uc_sta_is_enabled(
5861 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005862 hdd_ipa->sta_connected) {
5863 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005864 hdd_ipa_uc_offload_enable_disable(
5865 hdd_get_adapter(
5866 hdd_ipa->hdd_ctx,
5867 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005868 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005869 } else {
5870 qdf_mutex_release(&hdd_ipa->event_lock);
5871 }
Yun Parka37592b2016-06-11 17:10:28 -07005872
Yun Park312f71a2015-12-08 10:22:42 -08005873 return ret;
5874 }
5875 }
5876
5877 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005878
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305879 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005880
5881 meta.msg_type = type;
5882 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5883 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305884 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005885
5886 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305887 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005888 "msg_ex allocation failed");
5889 return -ENOMEM;
5890 }
5891 strlcpy(msg_ex->name, adapter->dev->name,
5892 IPA_RESOURCE_NAME_MAX);
5893 msg_ex->num_of_attribs = 1;
5894 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5895 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5896 msg_ex->attribs[0].offset =
5897 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5898 } else {
5899 msg_ex->attribs[0].offset =
5900 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5901 }
5902 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5903 IPA_MAC_ADDR_SIZE);
5904
5905 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5906
5907 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005908 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305909 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305910 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005911 return ret;
5912 }
5913 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005914 return ret;
5915
5916 case WLAN_CLIENT_DISCONNECT:
5917 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005918 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005919 "%s: IPA UC OFFLOAD NOT ENABLED",
5920 msg_ex->name);
5921 return 0;
5922 }
5923
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305924 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005925 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005926 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305927 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005928 "%s: STA ID %d NOT found, not valid",
5929 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005930 return 0;
5931 }
5932 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005933
Yun Park9b5030f2016-11-08 12:02:37 -08005934 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005935 if (!hdd_ipa->sap_num_connected_sta &&
5936 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005937 if ((false == hdd_ipa->resource_unloading)
5938 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305939 hdd_ipa->activated_fw_pipe) &&
5940 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005941 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5942 }
5943
Yun Park8f289c82016-10-18 16:38:21 -07005944 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005945
5946 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5947 hdd_ipa->sta_connected)
5948 hdd_ipa_uc_offload_enable_disable(
5949 hdd_get_adapter(hdd_ipa->hdd_ctx,
5950 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005951 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005952 } else {
5953 qdf_mutex_release(&hdd_ipa->event_lock);
5954 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005955 break;
5956
5957 default:
5958 return 0;
5959 }
5960
5961 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305962 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005963 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305964 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005965 return -ENOMEM;
5966 }
5967
5968 meta.msg_type = type;
5969 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5970 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5971
Srinivas Girigowda97852372017-03-06 16:52:59 -08005972 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005973 msg->name, meta.msg_type);
5974
5975 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5976
5977 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005978 hdd_err("%s: Evt: %d fail:%d",
5979 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305980 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005981 return ret;
5982 }
5983
5984 hdd_ipa->stats.num_send_msg++;
5985
5986end:
5987 return ret;
5988}
5989
5990/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005991 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005992 * @adapter: adapter upon which the event was received
5993 * @sta_id: station id for the event
5994 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5995 * @mac_address: MAC address associated with the event
5996 *
5997 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5998 *
5999 * Return: 0 on success, negative errno value on error
6000 */
6001int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
6002 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
6003{
6004 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006005 int ret = 0;
6006
6007 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07006008
Leo Changa202b522016-10-14 16:13:50 -07006009 /* Data path offload only support for STA and SAP mode */
6010 if ((QDF_STA_MODE == adapter->device_mode) ||
6011 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006012 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07006013
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006014 cds_ssr_unprotect(__func__);
6015
6016 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07006017}
6018
6019/**
6020 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
6021 * @hdd_ipa: Global HDD IPA context
6022 *
6023 * Return: None
6024 */
6025static void
6026hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
6027{
6028 unsigned int pending_event_count;
6029 struct ipa_uc_pending_event *pending_event = NULL;
6030
6031 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08006032 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07006033 "%s, Pending Event Count %d", __func__, pending_event_count);
6034 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08006035 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07006036 "%s, No Pending Event", __func__);
6037 return;
6038 }
6039
6040 qdf_list_remove_front(&hdd_ipa->pending_event,
6041 (qdf_list_node_t **)&pending_event);
6042 while (pending_event != NULL) {
6043 __hdd_ipa_wlan_evt(pending_event->adapter,
6044 pending_event->type,
6045 pending_event->sta_id,
6046 pending_event->mac_addr);
6047 qdf_mem_free(pending_event);
6048 pending_event = NULL;
6049 qdf_list_remove_front(&hdd_ipa->pending_event,
6050 (qdf_list_node_t **)&pending_event);
6051 }
6052}
6053
6054/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006055 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
6056 * @state: IPA RM state value
6057 *
6058 * Return: ASCII string representing the IPA RM state
6059 */
6060static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
6061{
6062 switch (state) {
6063 case HDD_IPA_RM_RELEASED:
6064 return "RELEASED";
6065 case HDD_IPA_RM_GRANT_PENDING:
6066 return "GRANT_PENDING";
6067 case HDD_IPA_RM_GRANTED:
6068 return "GRANTED";
6069 }
6070
6071 return "UNKNOWN";
6072}
6073
6074/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006075 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006076 * @hdd_ctx: HDD global context
6077 *
6078 * Allocate hdd_ipa resources, ipa pipe resource and register
6079 * wlan interface with IPA module.
6080 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306081 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006082 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006083static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006084{
6085 struct hdd_ipa_priv *hdd_ipa = NULL;
6086 int ret, i;
6087 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08006088 struct ol_txrx_pdev_t *pdev = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006089
6090 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306091 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092
Yun Parkbaa62862017-01-18 13:43:34 -08006093 ENTER();
6094
6095 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07006096 if (!pdev) {
6097 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
6098 goto fail_return;
6099 }
6100
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306101 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006102 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306103 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08006104 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006105 }
6106
6107 hdd_ctx->hdd_ipa = hdd_ipa;
6108 ghdd_ipa = hdd_ipa;
6109 hdd_ipa->hdd_ctx = hdd_ctx;
6110 hdd_ipa->num_iface = 0;
6111
6112 /* Create the interface context */
6113 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6114 iface_context = &hdd_ipa->iface_context[i];
6115 iface_context->hdd_ipa = hdd_ipa;
6116 iface_context->cons_client =
6117 hdd_ipa_adapter_2_client[i].cons_client;
6118 iface_context->prod_client =
6119 hdd_ipa_adapter_2_client[i].prod_client;
6120 iface_context->iface_id = i;
6121 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306122 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08006123 }
6124 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08006125 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
6126 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006127 }
6128
Leo Chang69c39692016-10-12 20:11:12 -07006129 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306130 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006131 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05306132 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08006133 qdf_list_create(&hdd_ipa->pending_event, 1000);
6134 qdf_mutex_create(&hdd_ipa->event_lock);
6135 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006136
6137 ret = hdd_ipa_setup_rm(hdd_ipa);
6138 if (ret)
6139 goto fail_setup_rm;
6140
6141 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
6142 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306143 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006144 hdd_ipa->sap_num_connected_sta = 0;
6145 hdd_ipa->ipa_tx_packets_diff = 0;
6146 hdd_ipa->ipa_rx_packets_diff = 0;
6147 hdd_ipa->ipa_p_tx_packets = 0;
6148 hdd_ipa->ipa_p_rx_packets = 0;
6149 hdd_ipa->resource_loading = false;
6150 hdd_ipa->resource_unloading = false;
6151 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07006152 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08006153 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006154 /* Setup IPA sys_pipe for MCC */
6155 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
6156 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6157 if (ret)
6158 goto fail_create_sys_pipe;
6159 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08006160 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
6161 goto fail_create_sys_pipe;
Manikandan Mohan2e803a02017-02-14 14:57:53 -08006162
6163 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6164 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
6165 hdd_ipa_uc_fw_op_event_handler);
6166 hdd_ipa->uc_op_work[i].msg = NULL;
6167 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006168 } else {
6169 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6170 if (ret)
6171 goto fail_create_sys_pipe;
6172 }
6173
Yun Parkbaa62862017-01-18 13:43:34 -08006174 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306175 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006176
6177fail_create_sys_pipe:
6178 hdd_ipa_destroy_rm_resource(hdd_ipa);
6179fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306180 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306181 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08006182 hdd_ctx->hdd_ipa = NULL;
6183 ghdd_ipa = NULL;
6184fail_return:
Yun Parkbaa62862017-01-18 13:43:34 -08006185 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306186 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006187}
6188
6189/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006190 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
6191 * @hdd_ctx: HDD global context
6192 *
6193 * Allocate hdd_ipa resources, ipa pipe resource and register
6194 * wlan interface with IPA module.
6195 *
6196 * Return: QDF_STATUS enumeration
6197 */
6198QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
6199{
6200 QDF_STATUS ret;
6201
6202 cds_ssr_protect(__func__);
6203 ret = __hdd_ipa_init(hdd_ctx);
6204 cds_ssr_unprotect(__func__);
6205
6206 return ret;
6207}
6208
Arun Khandavallicc544b32017-01-30 19:52:16 +05306209
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006210/**
Yun Parkf19e07d2015-11-20 11:34:27 -08006211 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
6212 * @hdd_ipa: pointer to HDD IPA struct
6213 *
6214 * Return: none
6215 */
Jeff Johnsond7720632016-10-05 16:04:32 -07006216static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08006217{
6218 struct ipa_uc_pending_event *pending_event = NULL;
6219
Anurag Chouhanffb21542016-02-17 14:33:03 +05306220 while (qdf_list_remove_front(&hdd_ipa->pending_event,
6221 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306222 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08006223 }
6224
Anurag Chouhanffb21542016-02-17 14:33:03 +05306225 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08006226}
6227
6228/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006229 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006230 * @hdd_ctx: HDD global context
6231 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306232 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006233 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006234static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006235{
6236 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
6237 int i;
6238 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05306239 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006240 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
6241
6242 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306243 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006244
6245 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
6246 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
6247 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6248 }
6249
6250 /* Teardown IPA sys_pipe for MCC */
6251 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
6252 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6253
6254 hdd_ipa_destroy_rm_resource(hdd_ipa);
6255
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006256 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006257
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306258 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006259
Nirav Shahcbc6d722016-03-01 16:24:53 +05306260 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
6261 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306262 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006263
6264 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07006265 if (pm_tx_cb->ipa_tx_desc)
6266 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006267
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306268 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006269 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306270 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006271
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306272 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006273 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006274
6275 /* destory the interface lock */
6276 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6277 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306278 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006279 }
6280
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006281 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08006282 if (ipa_uc_dereg_rdyCB())
6283 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
6284 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006285 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306286 qdf_mutex_destroy(&hdd_ipa->event_lock);
6287 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08006288 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006289
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006290 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6291 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
6292 hdd_ipa->uc_op_work[i].msg = NULL;
6293 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006294 }
6295
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306296 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006297 hdd_ctx->hdd_ipa = NULL;
6298
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306299 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006300}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006301
6302/**
6303 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
6304 * @hdd_ctx: HDD global context
6305 *
6306 * Return: QDF_STATUS enumeration
6307 */
6308QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
6309{
6310 QDF_STATUS ret;
6311
6312 cds_ssr_protect(__func__);
6313 ret = __hdd_ipa_cleanup(hdd_ctx);
6314 cds_ssr_unprotect(__func__);
6315
6316 return ret;
6317}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006318#endif /* IPA_OFFLOAD */