blob: 6bf3b6d495478635ecb763e88567bc775b014576 [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)
695 return;
696
697 uc_op_work->msg = msg;
698 schedule_work(&uc_op_work->work);
699}
700
701/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800702 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
703 * @ctrl: WDI control value
704 *
705 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
706 *
707 * Return: 0 on message send to ipa, -1 on failure
708 */
709static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
710{
711 struct ipa_msg_meta meta;
712 struct ipa_wlan_msg *ipa_msg;
713 int ret = 0;
714
715 /* WDI enable message to IPA */
716 meta.msg_len = sizeof(*ipa_msg);
717 ipa_msg = qdf_mem_malloc(meta.msg_len);
718 if (ipa_msg == NULL) {
719 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
720 "msg allocation failed");
721 return -ENOMEM;
722 }
723
724 if (ctrl == true)
725 meta.msg_type = WLAN_WDI_ENABLE;
726 else
727 meta.msg_type = WLAN_WDI_DISABLE;
728
Srinivas Girigowda97852372017-03-06 16:52:59 -0800729 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800730 "ipa_send_msg(Evt:%d)", meta.msg_type);
731 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
732 if (ret) {
733 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
734 "ipa_send_msg(Evt:%d)-fail=%d",
735 meta.msg_type, ret);
736 qdf_mem_free(ipa_msg);
737 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800738 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800739}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800740
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800741/**
742 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
743 * @hdd_ipa: HDD IPA local context
744 *
745 * Register IPA UC ready callback function to IPA kernel driver
746 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
747 * open WDI pipe after WLAN driver loading finished
748 *
749 * Return: 0 Success
750 * -EPERM Registration fail
751 */
752static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
753{
754 struct ipa_wdi_uc_ready_params uc_ready_param;
755 int ret = 0;
756
757 hdd_ipa->uc_loaded = false;
758 uc_ready_param.priv = (void *)hdd_ipa;
759 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
760 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
761 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
762 "UC Ready CB register fail");
763 return -EPERM;
764 }
765 if (true == uc_ready_param.is_uC_ready) {
Srinivas Girigowda2b5d47c2017-03-29 00:28:46 -0700766 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800767 hdd_ipa->uc_loaded = true;
768 } else {
769 ret = hdd_ipa_uc_send_wdi_control_msg(false);
770 }
771
772 return ret;
773}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800774#else
775static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
776 enum ipa_client_type client)
777{
778 /* Do nothing */
779}
780
781static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
782{
783 hdd_ipa->uc_loaded = true;
784 return 0;
785}
786
787static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
788{
789 return 0;
790}
791#endif
792
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793/**
794 * hdd_ipa_is_enabled() - Is IPA enabled?
795 * @hdd_ctx: Global HDD context
796 *
797 * Return: true if IPA is enabled, false otherwise
798 */
799bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
800{
801 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
802}
803
804/**
805 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
806 * @hdd_ctx: Global HDD context
807 *
808 * Return: true if IPA uC offload is enabled, false otherwise
809 */
810bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
811{
812 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
813}
814
815/**
816 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
817 * @hdd_ctx: Global HDD context
818 *
819 * Return: true if STA mode IPA uC offload is enabled, false otherwise
820 */
821static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
822{
823 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
824}
825
826/**
Guolei Bianca144d82016-11-10 11:07:42 +0800827 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
828 * @hdd_ipa: Global HDD IPA context
829 *
830 * Return: None
831 */
Guolei Bianca144d82016-11-10 11:07:42 +0800832static inline void hdd_ipa_uc_sta_reset_sta_connected(
833 struct hdd_ipa_priv *hdd_ipa)
834{
Yun Park637d6482016-10-05 10:51:33 -0700835 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800836 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700837 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800838}
Guolei Bianca144d82016-11-10 11:07:42 +0800839
840/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800841 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
842 * @hdd_ipa: Global HDD IPA context
843 *
844 * Return: true if pre-filter is enabled, otherwise false
845 */
846static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
847{
848 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
849 HDD_IPA_PRE_FILTER_ENABLE_MASK);
850}
851
852/**
853 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
854 * @hdd_ipa: Global HDD IPA context
855 *
856 * Return: true if IPv6 is enabled, otherwise false
857 */
858static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
859{
860 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
861}
862
863/**
864 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
865 * @hdd_ipa: Global HDD IPA context
866 *
867 * Return: true if resource manager is enabled, otherwise false
868 */
869static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
870{
871 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
872}
873
874/**
875 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
876 * @hdd_ipa: Global HDD IPA context
877 *
878 * Return: true if resource manager is enabled, otherwise false
879 */
880static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
881{
882 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
883}
884
885/**
886 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
887 * @hdd_ipa: Global HDD IPA context
888 *
889 * Return: true if clock scaling is enabled, otherwise false
890 */
891static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
892{
893 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
894 HDD_IPA_CLK_SCALING_ENABLE_MASK |
895 HDD_IPA_RM_ENABLE_MASK);
896}
897
898/**
899 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
900 * @ctext: pointer to hdd context.
901 *
902 * If rt debug enabled, periodically called, and fill debug buffer
903 *
904 * Return: none
905 */
906static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
907{
908 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
909 struct hdd_ipa_priv *hdd_ipa;
910 struct uc_rt_debug_info *dump_info = NULL;
911
912 if (wlan_hdd_validate_context(hdd_ctx))
913 return;
914
915 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800916 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917 "%s: IPA UC is not enabled", __func__);
918 return;
919 }
920
921 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
922
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530923 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924 dump_info = &hdd_ipa->rt_bug_buffer[
925 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
926
Deepthi Gowri6acee342016-10-28 15:00:38 +0530927 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800928 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
929 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
930 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800932 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
933 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
935 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530936 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800937
Anurag Chouhan210db072016-02-22 18:42:15 +0530938 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800939 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
940}
941
942/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700943 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 * @hdd_ctx: pointer to hdd context.
945 *
946 * If rt debug enabled, dump debug buffer contents based on requirement
947 *
948 * Return: none
949 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700950static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951{
952 struct hdd_ipa_priv *hdd_ipa;
953 unsigned int dump_count;
954 unsigned int dump_index;
955 struct uc_rt_debug_info *dump_info = NULL;
956
957 if (wlan_hdd_validate_context(hdd_ctx))
958 return;
959
960 hdd_ipa = hdd_ctx->hdd_ipa;
961 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800962 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800963 "%s: IPA UC is not enabled", __func__);
964 return;
965 }
966
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530967 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800968 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530969 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800970 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800971
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530972 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973 for (dump_count = 0;
974 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
975 dump_count++) {
976 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
977 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
978 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530979 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530980 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800981 dump_info->time, dump_info->ipa_excep_count,
982 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800983 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800984 dump_info->rx_destructor_call,
985 dump_info->rx_discard_count);
986 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530987 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530988 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
990}
991
992/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700993 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
994 * __hdd_ipa_uc_rt_debug_host_dump
995 * @hdd_ctx: pointer to hdd context.
996 *
997 * If rt debug enabled, dump debug buffer contents based on requirement
998 *
999 * Return: none
1000 */
1001void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
1002{
1003 cds_ssr_protect(__func__);
1004 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1005 cds_ssr_unprotect(__func__);
1006}
1007
1008/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001009 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
1010 * @ctext: pointer to hdd context.
1011 *
1012 * periodically called by timer expire
1013 * will try to alloc dummy memory and detect out of memory condition
1014 * if out of memory detected, dump wlan-ipa stats
1015 *
1016 * Return: none
1017 */
1018static void hdd_ipa_uc_rt_debug_handler(void *ctext)
1019{
1020 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001021 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001022 void *dummy_ptr = NULL;
1023
1024 if (wlan_hdd_validate_context(hdd_ctx))
1025 return;
1026
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001027 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1028
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001029 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001030 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001031 return;
1032 }
1033
1034 /* Allocate dummy buffer periodically and free immediately. this will
1035 * proactively detect OOM and if allocation fails dump ipa stats
1036 */
1037 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
1038 GFP_KERNEL | GFP_ATOMIC);
1039 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001040 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1041 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -07001042 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
1043 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044 } else {
1045 kfree(dummy_ptr);
1046 }
1047
Anurag Chouhan210db072016-02-22 18:42:15 +05301048 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001049 HDD_IPA_UC_RT_DEBUG_PERIOD);
1050}
1051
1052/**
Yun Parkb187d542016-11-14 18:10:04 -08001053 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054 * @skb: packet pinter
1055 *
1056 * when free data packet, will be invoked by wlan client and will increase
1057 * free counter
1058 *
1059 * Return: none
1060 */
Jeff Johnsond7720632016-10-05 16:04:32 -07001061static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001062{
1063 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301064 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 "%s: invalid hdd context", __func__);
1066 return;
1067 }
1068
1069 ghdd_ipa->ipa_rx_destructor_count++;
1070}
1071
1072/**
Yun Parkb187d542016-11-14 18:10:04 -08001073 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001074 * @hdd_ctx: hdd main context
1075 *
1076 * free all rt debugging resources
1077 *
1078 * Return: none
1079 */
1080static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
1081{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001082 struct hdd_ipa_priv *hdd_ipa;
1083
1084 if (wlan_hdd_validate_context(hdd_ctx))
1085 return;
1086
1087 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001088
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301089 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001090
1091 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001092 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093 return;
1094 }
1095
Anurag Chouhan210db072016-02-22 18:42:15 +05301096 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001097 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1098 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1099 }
1100 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1101
1102 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301103 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1104 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301106 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107}
1108
1109/**
Yun Parkb187d542016-11-14 18:10:04 -08001110 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001111 * @hdd_ctx: hdd main context
1112 *
1113 * alloc and initialize all rt debugging resources
1114 *
1115 * Return: none
1116 */
1117static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
1118{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001119 struct hdd_ipa_priv *hdd_ipa;
1120
1121 if (wlan_hdd_validate_context(hdd_ctx))
1122 return;
1123
1124 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001125
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301126 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001127 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301128 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001129 sizeof(struct uc_rt_debug_info) *
1130 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1131 hdd_ipa->ipa_tx_forward = 0;
1132 hdd_ipa->ipa_rx_discard = 0;
1133 hdd_ipa->ipa_rx_net_send_count = 0;
1134 hdd_ipa->ipa_rx_internel_drop_count = 0;
1135 hdd_ipa->ipa_rx_destructor_count = 0;
1136
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001137 /* Reatime debug enable on feature enable */
1138 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001139 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140 return;
1141 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001142
1143 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1144 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1145 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1146 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1147
Anurag Chouhan210db072016-02-22 18:42:15 +05301148 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001149 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301150 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001151 HDD_IPA_UC_RT_DEBUG_PERIOD);
1152
1153}
1154
1155/**
Yun Parkb187d542016-11-14 18:10:04 -08001156 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1157 * @hdd_ipa: HDD IPA struct
1158 *
1159 * Dump entries in struct hdd_ipa
1160 *
1161 * Return: none
1162 */
1163static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1164{
1165 int i;
1166
1167 /* HDD IPA */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001168 hdd_info("==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001169 "num_iface: %d\n"
1170 "rm_state: %d\n"
1171 "rm_lock: %p\n"
1172 "uc_rm_work: %p\n"
1173 "uc_op_work: %p\n"
1174 "wake_lock: %p\n"
1175 "wake_lock_work: %p\n"
1176 "wake_lock_released: %d\n"
1177 "prod_client: %d\n"
1178 "tx_ref_cnt: %d\n"
1179 "pm_queue_head----\n"
1180 "\thead: %p\n"
1181 "\ttail: %p\n"
1182 "\tqlen: %d\n"
1183 "pm_work: %p\n"
1184 "pm_lock: %p\n"
1185 "suspended: %d\n",
1186 hdd_ipa->num_iface,
1187 hdd_ipa->rm_state,
1188 &hdd_ipa->rm_lock,
1189 &hdd_ipa->uc_rm_work,
1190 &hdd_ipa->uc_op_work,
1191 &hdd_ipa->wake_lock,
1192 &hdd_ipa->wake_lock_work,
1193 hdd_ipa->wake_lock_released,
1194 hdd_ipa->prod_client,
1195 hdd_ipa->tx_ref_cnt.counter,
1196 hdd_ipa->pm_queue_head.head,
1197 hdd_ipa->pm_queue_head.tail,
1198 hdd_ipa->pm_queue_head.qlen,
1199 &hdd_ipa->pm_work,
1200 &hdd_ipa->pm_lock,
1201 hdd_ipa->suspended);
Yun Park52b2b992016-09-22 15:49:51 -07001202 hdd_err("\nq_lock: %p\n"
Yun Parkb187d542016-11-14 18:10:04 -08001203 "pend_desc_head----\n"
1204 "\tnext: %p\n"
1205 "\tprev: %p\n"
1206 "hdd_ctx: %p\n"
1207 "debugfs_dir: %p\n"
1208 "stats: %p\n"
1209 "ipv4_notifier: %p\n"
1210 "curr_prod_bw: %d\n"
1211 "curr_cons_bw: %d\n"
1212 "activated_fw_pipe: %d\n"
1213 "sap_num_connected_sta: %d\n"
1214 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001215 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001216 hdd_ipa->pend_desc_head.next,
1217 hdd_ipa->pend_desc_head.prev,
1218 hdd_ipa->hdd_ctx,
1219 hdd_ipa->debugfs_dir,
1220 &hdd_ipa->stats,
1221 &hdd_ipa->ipv4_notifier,
1222 hdd_ipa->curr_prod_bw,
1223 hdd_ipa->curr_cons_bw,
1224 hdd_ipa->activated_fw_pipe,
1225 hdd_ipa->sap_num_connected_sta,
1226 (unsigned int)hdd_ipa->sta_connected
1227 );
Srinivas Girigowda97852372017-03-06 16:52:59 -08001228 hdd_info("\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001229 "rx_pipe_handle: 0x%x\n"
1230 "resource_loading: %d\n"
1231 "resource_unloading: %d\n"
1232 "pending_cons_req: %d\n"
1233 "pending_event----\n"
1234 "\tanchor.next: %p\n"
1235 "\tanchor.prev: %p\n"
1236 "\tcount: %d\n"
1237 "\tmax_size: %d\n"
1238 "event_lock: %p\n"
1239 "ipa_tx_packets_diff: %d\n"
1240 "ipa_rx_packets_diff: %d\n"
1241 "ipa_p_tx_packets: %d\n"
1242 "ipa_p_rx_packets: %d\n"
1243 "stat_req_reason: %d\n",
1244 hdd_ipa->tx_pipe_handle,
1245 hdd_ipa->rx_pipe_handle,
1246 hdd_ipa->resource_loading,
1247 hdd_ipa->resource_unloading,
1248 hdd_ipa->pending_cons_req,
1249 hdd_ipa->pending_event.anchor.next,
1250 hdd_ipa->pending_event.anchor.prev,
1251 hdd_ipa->pending_event.count,
1252 hdd_ipa->pending_event.max_size,
1253 &hdd_ipa->event_lock,
1254 hdd_ipa->ipa_tx_packets_diff,
1255 hdd_ipa->ipa_rx_packets_diff,
1256 hdd_ipa->ipa_p_tx_packets,
1257 hdd_ipa->ipa_p_rx_packets,
1258 hdd_ipa->stat_req_reason);
1259
Srinivas Girigowda97852372017-03-06 16:52:59 -08001260 hdd_info("assoc_stas_map([id]is_reserved/sta_id): ");
Yun Parkb187d542016-11-14 18:10:04 -08001261 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001262 hdd_info(" [%d]%d/%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001263 hdd_ipa->assoc_stas_map[i].is_reserved,
1264 hdd_ipa->assoc_stas_map[i].sta_id);
1265 }
1266}
1267
1268/**
1269 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1270 * @hdd_ipa: HDD IPA struct
1271 *
1272 * Dump entire struct hdd_ipa_sys_pipe
1273 *
1274 * Return: none
1275 */
1276static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1277{
1278 int i;
1279
1280 /* IPA SYS Pipes */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001281 hdd_info("==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001282
1283 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1284 struct hdd_ipa_sys_pipe *sys_pipe;
1285 struct ipa_sys_connect_params *ipa_sys_params;
1286
1287 sys_pipe = &hdd_ipa->sys_pipe[i];
1288 ipa_sys_params = &sys_pipe->ipa_sys_params;
1289
Srinivas Girigowda97852372017-03-06 16:52:59 -08001290 hdd_info("sys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001291 "\tconn_hdl: 0x%x\n"
1292 "\tconn_hdl_valid: %d\n"
1293 "\tnat_en: %d\n"
1294 "\thdr_len %d\n"
1295 "\thdr_additional_const_len: %d\n"
1296 "\thdr_ofst_pkt_size_valid: %d\n"
1297 "\thdr_ofst_pkt_size: %d\n"
1298 "\thdr_little_endian: %d\n"
1299 "\tmode: %d\n"
1300 "\tclient: %d\n"
1301 "\tdesc_fifo_sz: %d\n"
1302 "\tpriv: %p\n"
1303 "\tnotify: %p\n"
1304 "\tskip_ep_cfg: %d\n"
1305 "\tkeep_ipa_awake: %d\n",
1306 i,
1307 sys_pipe->conn_hdl,
1308 sys_pipe->conn_hdl_valid,
1309 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1310 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1311 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1312 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1313 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1314 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1315 ipa_sys_params->ipa_ep_cfg.mode.mode,
1316 ipa_sys_params->client,
1317 ipa_sys_params->desc_fifo_sz,
1318 ipa_sys_params->priv,
1319 ipa_sys_params->notify,
1320 ipa_sys_params->skip_ep_cfg,
1321 ipa_sys_params->keep_ipa_awake);
1322 }
1323}
1324
1325/**
1326 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1327 * @hdd_ipa: HDD IPA struct
1328 *
1329 * Dump entire struct hdd_ipa_iface_context
1330 *
1331 * Return: none
1332 */
1333static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1334{
1335 int i;
1336
1337 /* IPA Interface Contexts */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001338 hdd_info("==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001339
1340 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1341 struct hdd_ipa_iface_context *iface_context;
1342
1343 iface_context = &hdd_ipa->iface_context[i];
1344
Srinivas Girigowda97852372017-03-06 16:52:59 -08001345 hdd_info("iface_context[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001346 "\thdd_ipa: %p\n"
1347 "\tadapter: %p\n"
1348 "\ttl_context: %p\n"
1349 "\tcons_client: %d\n"
1350 "\tprod_client: %d\n"
1351 "\tiface_id: %d\n"
1352 "\tsta_id: %d\n"
1353 "\tinterface_lock: %p\n"
1354 "\tifa_address: 0x%x\n",
1355 i,
1356 iface_context->hdd_ipa,
1357 iface_context->adapter,
1358 iface_context->tl_context,
1359 iface_context->cons_client,
1360 iface_context->prod_client,
1361 iface_context->iface_id,
1362 iface_context->sta_id,
1363 &iface_context->interface_lock,
1364 iface_context->ifa_address);
1365 }
1366}
1367
1368/**
1369 * hdd_ipa_dump_info() - dump HDD IPA struct
1370 * @pHddCtx: hdd main context
1371 *
1372 * Dump entire struct hdd_ipa
1373 *
1374 * Return: none
1375 */
1376void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1377{
1378 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1379
1380 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1381 hdd_ipa_dump_sys_pipe(hdd_ipa);
1382 hdd_ipa_dump_iface_context(hdd_ipa);
1383}
1384
1385/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001386 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1387 * enabled
1388 *
1389 * This routine is called to set TX flow info if IPA is enabled
1390 *
1391 * Return: None
1392 */
1393void hdd_ipa_set_tx_flow_info(void)
1394{
1395 hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL;
1396 QDF_STATUS status;
1397 hdd_adapter_t *adapter;
1398 hdd_station_ctx_t *pHddStaCtx;
1399 hdd_ap_ctx_t *hdd_ap_ctx;
1400 hdd_hostapd_state_t *hostapd_state;
1401 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1402 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1403 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1404 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1405 const char *p2pMode = "DEV";
1406 hdd_context_t *hdd_ctx;
1407 cds_context_type *cds_ctx;
1408#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1409 uint8_t targetChannel = 0;
1410 uint8_t preAdapterChannel = 0;
1411 uint8_t channel24;
1412 uint8_t channel5;
1413 hdd_adapter_t *preAdapterContext = NULL;
1414 hdd_adapter_t *adapter2_4 = NULL;
1415 hdd_adapter_t *adapter5 = NULL;
1416 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1417#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1418 struct wlan_objmgr_psoc *psoc;
1419
1420 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1421 if (!hdd_ctx) {
1422 cds_err("HDD context is NULL");
1423 return;
1424 }
1425
1426 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1427 if (!cds_ctx) {
1428 cds_err("Invalid CDS Context");
1429 return;
1430 }
1431
1432 psoc = hdd_ctx->hdd_psoc;
1433 status = hdd_get_front_adapter(hdd_ctx, &adapterNode);
1434 while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) {
1435 adapter = adapterNode->pAdapter;
1436 switch (adapter->device_mode) {
1437 case QDF_STA_MODE:
1438 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1439 if (eConnectionState_Associated ==
1440 pHddStaCtx->conn_info.connState) {
1441 staChannel =
1442 pHddStaCtx->conn_info.operationChannel;
1443 qdf_copy_macaddr(&staBssid,
1444 &pHddStaCtx->conn_info.bssId);
1445#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1446 targetChannel = staChannel;
1447#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1448 }
1449 break;
1450 case QDF_P2P_CLIENT_MODE:
1451 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1452 if (eConnectionState_Associated ==
1453 pHddStaCtx->conn_info.connState) {
1454 p2pChannel =
1455 pHddStaCtx->conn_info.operationChannel;
1456 qdf_copy_macaddr(&p2pBssid,
1457 &pHddStaCtx->conn_info.bssId);
1458 p2pMode = "CLI";
1459#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1460 targetChannel = p2pChannel;
1461#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1462 }
1463 break;
1464 case QDF_P2P_GO_MODE:
1465 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1466 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1467 if (hostapd_state->bssState == BSS_START
1468 && hostapd_state->qdf_status ==
1469 QDF_STATUS_SUCCESS) {
1470 p2pChannel = hdd_ap_ctx->operatingChannel;
1471 qdf_copy_macaddr(&p2pBssid,
1472 &adapter->macAddressCurrent);
1473#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1474 targetChannel = p2pChannel;
1475#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1476 }
1477 p2pMode = "GO";
1478 break;
1479 case QDF_SAP_MODE:
1480 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1481 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1482 if (hostapd_state->bssState == BSS_START
1483 && hostapd_state->qdf_status ==
1484 QDF_STATUS_SUCCESS) {
1485 apChannel = hdd_ap_ctx->operatingChannel;
1486 qdf_copy_macaddr(&apBssid,
1487 &adapter->macAddressCurrent);
1488#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1489 targetChannel = apChannel;
1490#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1491 }
1492 break;
1493 case QDF_IBSS_MODE:
1494 default:
1495 break;
1496 }
1497#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1498 if (targetChannel) {
1499 /*
1500 * This is first adapter detected as active
1501 * set as default for none concurrency case
1502 */
1503 if (!preAdapterChannel) {
1504 /* If IPA UC data path is enabled,
1505 * target should reserve extra tx descriptors
1506 * for IPA data path.
1507 * Then host data path should allow less TX
1508 * packet pumping in case IPA
1509 * data path enabled
1510 */
1511 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1512 (QDF_SAP_MODE == adapter->device_mode)) {
1513 adapter->tx_flow_low_watermark =
1514 hdd_ctx->config->TxFlowLowWaterMark +
1515 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1516 } else {
1517 adapter->tx_flow_low_watermark =
1518 hdd_ctx->config->
1519 TxFlowLowWaterMark;
1520 }
1521 adapter->tx_flow_high_watermark_offset =
1522 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1523 cdp_fc_ll_set_tx_pause_q_depth(soc,
1524 adapter->sessionId,
1525 hdd_ctx->config->TxFlowMaxQueueDepth);
1526 cds_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
1527 adapter->device_mode,
1528 targetChannel,
1529 adapter->tx_flow_low_watermark,
1530 adapter->tx_flow_low_watermark +
1531 adapter->tx_flow_high_watermark_offset,
1532 hdd_ctx->config->TxFlowMaxQueueDepth);
1533 preAdapterChannel = targetChannel;
1534 preAdapterContext = adapter;
1535 } else {
1536 /*
1537 * SCC, disable TX flow control for both
1538 * SCC each adapter cannot reserve dedicated
1539 * channel resource, as a result, if any adapter
1540 * blocked OS Q by flow control,
1541 * blocked adapter will lost chance to recover
1542 */
1543 if (preAdapterChannel == targetChannel) {
1544 /* Current adapter */
1545 adapter->tx_flow_low_watermark = 0;
1546 adapter->
1547 tx_flow_high_watermark_offset = 0;
1548 cdp_fc_ll_set_tx_pause_q_depth(soc,
1549 adapter->sessionId,
1550 hdd_ctx->config->
1551 TxHbwFlowMaxQueueDepth);
1552 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1553 hdd_device_mode_to_string(
1554 adapter->device_mode),
1555 adapter->device_mode,
1556 targetChannel,
1557 adapter->tx_flow_low_watermark,
1558 adapter->tx_flow_low_watermark +
1559 adapter->
1560 tx_flow_high_watermark_offset,
1561 hdd_ctx->config->
1562 TxHbwFlowMaxQueueDepth);
1563
1564 if (!preAdapterContext) {
1565 cds_err("SCC: Previous adapter context NULL");
1566 continue;
1567 }
1568
1569 /* Previous adapter */
1570 preAdapterContext->
1571 tx_flow_low_watermark = 0;
1572 preAdapterContext->
1573 tx_flow_high_watermark_offset = 0;
1574 cdp_fc_ll_set_tx_pause_q_depth(soc,
1575 preAdapterContext->sessionId,
1576 hdd_ctx->config->
1577 TxHbwFlowMaxQueueDepth);
1578 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1579 hdd_device_mode_to_string(
1580 preAdapterContext->device_mode
1581 ),
1582 preAdapterContext->device_mode,
1583 targetChannel,
1584 preAdapterContext->
1585 tx_flow_low_watermark,
1586 preAdapterContext->
1587 tx_flow_low_watermark +
1588 preAdapterContext->
1589 tx_flow_high_watermark_offset,
1590 hdd_ctx->config->
1591 TxHbwFlowMaxQueueDepth);
1592 }
1593 /*
1594 * MCC, each adapter will have dedicated
1595 * resource
1596 */
1597 else {
1598 /* current channel is 2.4 */
1599 if (targetChannel <=
1600 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1601 channel24 = targetChannel;
1602 channel5 = preAdapterChannel;
1603 adapter2_4 = adapter;
1604 adapter5 = preAdapterContext;
1605 } else {
1606 /* Current channel is 5 */
1607 channel24 = preAdapterChannel;
1608 channel5 = targetChannel;
1609 adapter2_4 = preAdapterContext;
1610 adapter5 = adapter;
1611 }
1612
1613 if (!adapter5) {
1614 cds_err("MCC: 5GHz adapter context NULL");
1615 continue;
1616 }
1617 adapter5->tx_flow_low_watermark =
1618 hdd_ctx->config->
1619 TxHbwFlowLowWaterMark;
1620 adapter5->
1621 tx_flow_high_watermark_offset =
1622 hdd_ctx->config->
1623 TxHbwFlowHighWaterMarkOffset;
1624 cdp_fc_ll_set_tx_pause_q_depth(soc,
1625 adapter5->sessionId,
1626 hdd_ctx->config->
1627 TxHbwFlowMaxQueueDepth);
1628 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1629 hdd_device_mode_to_string(
1630 adapter5->device_mode),
1631 adapter5->device_mode,
1632 channel5,
1633 adapter5->tx_flow_low_watermark,
1634 adapter5->
1635 tx_flow_low_watermark +
1636 adapter5->
1637 tx_flow_high_watermark_offset,
1638 hdd_ctx->config->
1639 TxHbwFlowMaxQueueDepth);
1640
1641 if (!adapter2_4) {
1642 cds_err("MCC: 2.4GHz adapter context NULL");
1643 continue;
1644 }
1645 adapter2_4->tx_flow_low_watermark =
1646 hdd_ctx->config->
1647 TxLbwFlowLowWaterMark;
1648 adapter2_4->
1649 tx_flow_high_watermark_offset =
1650 hdd_ctx->config->
1651 TxLbwFlowHighWaterMarkOffset;
1652 cdp_fc_ll_set_tx_pause_q_depth(soc,
1653 adapter2_4->sessionId,
1654 hdd_ctx->config->
1655 TxLbwFlowMaxQueueDepth);
1656 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1657 hdd_device_mode_to_string(
1658 adapter2_4->device_mode),
1659 adapter2_4->device_mode,
1660 channel24,
1661 adapter2_4->
1662 tx_flow_low_watermark,
1663 adapter2_4->
1664 tx_flow_low_watermark +
1665 adapter2_4->
1666 tx_flow_high_watermark_offset,
1667 hdd_ctx->config->
1668 TxLbwFlowMaxQueueDepth);
1669
1670 }
1671 }
1672 }
1673 targetChannel = 0;
1674#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1675 status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext);
1676 adapterNode = pNext;
1677 }
1678 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1679}
1680
1681/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001682 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001683 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001684 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1685 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686 *
1687 * Return: true if IPA is enabled, false otherwise
1688 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001689static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001690 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1691{
1692 struct hdd_ipa_priv *hdd_ipa;
1693
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694 *ipa_tx_diff = 0;
1695 *ipa_rx_diff = 0;
1696
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001697 if (wlan_hdd_validate_context(hdd_ctx))
1698 return;
1699
1700 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1701
1702 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1703 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001704 return;
1705 }
1706
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301707 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001708 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1709 (false == hdd_ipa->resource_loading)) {
1710 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1711 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001712 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001713 *ipa_tx_diff, *ipa_rx_diff);
1714 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301715 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716}
1717
1718/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001719 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1720 * @hdd_ctx: Global HDD context
1721 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1722 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1723 *
1724 * Return: true if IPA is enabled, false otherwise
1725 */
1726void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1727 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1728{
1729 cds_ssr_protect(__func__);
1730 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1731 cds_ssr_unprotect(__func__);
1732}
1733
1734/**
1735 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736 * @adapter: network adapter
1737 * @reason: STAT REQ Reason
1738 *
1739 * Return: None
1740 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001741static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001743 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001744 struct hdd_ipa_priv *hdd_ipa;
1745
Yun Park637d6482016-10-05 10:51:33 -07001746 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001747 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001749 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1750
1751 if (wlan_hdd_validate_context(hdd_ctx))
1752 return;
1753
1754 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1755 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1756 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757 return;
1758 }
1759
Yun Parkb187d542016-11-14 18:10:04 -08001760 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301761 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1763 (false == hdd_ipa->resource_loading)) {
1764 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07001765 qdf_mutex_release(&hdd_ipa->ipa_lock);
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001766 sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter),
1767 adapter->sessionId,
1768 WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001770 } else {
1771 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001772 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001773}
1774
1775/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001776 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1777 * @adapter: network adapter
1778 * @reason: STAT REQ Reason
1779 *
1780 * Return: None
1781 */
1782void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1783{
1784 cds_ssr_protect(__func__);
1785 __hdd_ipa_uc_stat_request(adapter, reason);
1786 cds_ssr_unprotect(__func__);
1787}
1788
Yun Park637d6482016-10-05 10:51:33 -07001789#ifdef FEATURE_METERING
1790/**
1791 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
1792 * @adapter: network adapter
1793 * @reset_stats: reset stat countis after response
1794 *
1795 * Return: None
1796 */
1797void hdd_ipa_uc_sharing_stats_request(hdd_adapter_t *adapter,
1798 uint8_t reset_stats)
1799{
1800 hdd_context_t *pHddCtx;
1801 struct hdd_ipa_priv *hdd_ipa;
1802
1803 if (!adapter)
1804 return;
1805
1806 pHddCtx = adapter->pHddCtx;
1807 hdd_ipa = pHddCtx->hdd_ipa;
1808 if (!hdd_ipa_is_enabled(pHddCtx) ||
1809 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1810 return;
1811 }
1812
1813 HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats);
1814 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001815 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001816 qdf_mutex_release(&hdd_ipa->ipa_lock);
1817 wma_cli_set_command(
1818 (int)adapter->sessionId,
1819 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
1820 reset_stats, VDEV_CMD);
1821 } else {
1822 qdf_mutex_release(&hdd_ipa->ipa_lock);
1823 }
1824}
1825
1826/**
1827 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
1828 * @adapter: network adapter
1829 * @set_quota: when 1, FW starts quota monitoring
1830 * @quota_bytes: quota limit in bytes
1831 *
1832 * Return: None
1833 */
1834void hdd_ipa_uc_set_quota(hdd_adapter_t *adapter, uint8_t set_quota,
1835 uint64_t quota_bytes)
1836{
1837 hdd_context_t *pHddCtx;
1838 struct hdd_ipa_priv *hdd_ipa;
1839
1840 if (!adapter)
1841 return;
1842
1843 pHddCtx = adapter->pHddCtx;
1844 hdd_ipa = pHddCtx->hdd_ipa;
1845 if (!hdd_ipa_is_enabled(pHddCtx) ||
1846 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1847 return;
1848 }
1849
1850 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
1851 set_quota, quota_bytes);
1852
1853 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001854 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001855 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park327e7812017-02-14 15:18:10 -08001856 wma_cli_set2_command(
Yun Park637d6482016-10-05 10:51:33 -07001857 (int)adapter->sessionId,
1858 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
Yun Park327e7812017-02-14 15:18:10 -08001859 (set_quota ? quota_bytes&0xffffffff : 0),
1860 (set_quota ? quota_bytes>>32 : 0),
1861 VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001862 } else {
1863 qdf_mutex_release(&hdd_ipa->ipa_lock);
1864 }
1865}
1866#endif
1867
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001868/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001869 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1870 * @hdd_ipa: Global HDD IPA context
1871 * @sta_add: Should station be added
1872 * @sta_id: ID of the station being queried
1873 *
1874 * Return: true if the station was found
1875 */
1876static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1877 bool sta_add, uint8_t sta_id)
1878{
1879 bool sta_found = false;
1880 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001881
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001882 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1883 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1884 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1885 sta_found = true;
1886 break;
1887 }
1888 }
1889 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301890 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891 "%s: STA ID %d already exist, cannot add",
1892 __func__, sta_id);
1893 return sta_found;
1894 }
1895 if (sta_add) {
1896 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1897 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1898 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1899 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1900 return sta_found;
1901 }
1902 }
1903 }
1904 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301905 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001906 "%s: STA ID %d does not exist, cannot delete",
1907 __func__, sta_id);
1908 return sta_found;
1909 }
1910 if (!sta_add) {
1911 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1912 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1913 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1914 hdd_ipa->assoc_stas_map[idx].is_reserved =
1915 false;
1916 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1917 return sta_found;
1918 }
1919 }
1920 }
1921 return sta_found;
1922}
1923
1924/**
1925 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1926 * @hdd_ipa: Global HDD IPA context
1927 *
1928 * Return: 0 on success, negative errno if error
1929 */
1930static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1931{
1932 int result;
1933 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001934 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001935
1936 /* ACTIVATE TX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001937 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001938 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1939 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001940 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1941 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301942 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001943 "%s: Enable TX PIPE fail, code %d",
1944 __func__, result);
1945 return result;
1946 }
1947 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1948 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301949 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950 "%s: Resume TX PIPE fail, code %d",
1951 __func__, result);
1952 return result;
1953 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001954 cdp_ipa_set_active(soc,
1955 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1956 true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001957
1958 /* ACTIVATE RX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001959 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001960 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1961 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1963 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301964 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965 "%s: Enable RX PIPE fail, code %d",
1966 __func__, result);
1967 return result;
1968 }
1969 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1970 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301971 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972 "%s: Resume RX PIPE fail, code %d",
1973 __func__, result);
1974 return result;
1975 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001976 cdp_ipa_set_active(soc,
1977 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1978 true, false);
Leo Change3e49442015-10-26 20:07:13 -07001979 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001980 return 0;
1981}
1982
1983/**
1984 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1985 * @hdd_ipa: Global HDD IPA context
1986 *
1987 * Return: 0 on success, negative errno if error
1988 */
1989static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1990{
1991 int result;
1992
Leo Change3e49442015-10-26 20:07:13 -07001993 hdd_ipa->ipa_pipes_down = true;
1994
Srinivas Girigowda97852372017-03-06 16:52:59 -08001995 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001996 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
1997 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301998 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999 "%s: Suspend RX PIPE fail, code %d",
2000 __func__, result);
2001 return result;
2002 }
2003 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
2004 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302005 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 "%s: Disable RX PIPE fail, code %d",
2007 __func__, result);
2008 return result;
2009 }
2010
Srinivas Girigowda97852372017-03-06 16:52:59 -08002011 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
2013 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302014 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015 "%s: Suspend TX PIPE fail, code %d",
2016 __func__, result);
2017 return result;
2018 }
2019 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
2020 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302021 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002022 "%s: Disable TX PIPE fail, code %d",
2023 __func__, result);
2024 return result;
2025 }
2026
2027 return 0;
2028}
2029
2030/**
2031 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
2032 * @hdd_ipa: Global HDD IPA context
2033 *
2034 * Return: 0 on success, negative errno if error
2035 */
2036static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
2037{
2038 hdd_ipa->activated_fw_pipe = 0;
2039 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07002040
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002041 /* If RM feature enabled
2042 * Request PROD Resource first
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002043 * PROD resource may return sync or async manners
2044 */
Yun Park4cab6ee2015-10-27 11:43:40 -07002045 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
2046 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
2047 /* RM PROD request sync return
2048 * enable pipe immediately
2049 */
2050 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302051 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07002052 "%s: IPA WDI Pipe activation failed",
2053 __func__);
2054 hdd_ipa->resource_loading = false;
2055 return -EBUSY;
2056 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002057 }
2058 } else {
2059 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07002060 * Just enabled all the PIPEs
2061 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302063 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07002064 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002065 __func__);
2066 hdd_ipa->resource_loading = false;
2067 return -EBUSY;
2068 }
2069 hdd_ipa->resource_loading = false;
2070 }
Yun Park4cab6ee2015-10-27 11:43:40 -07002071
Srinivas Girigowda97852372017-03-06 16:52:59 -08002072 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07002073 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002074 return 0;
2075}
2076
2077/**
2078 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
2079 * @hdd_ipa: Global HDD IPA context
2080 *
2081 * Return: None
2082 */
2083static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
2084{
2085 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07002086 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087
Yun Park7c4f31b2016-11-30 10:09:21 -08002088 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
2089 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2090 QDF_ASSERT(0);
2091 return;
2092 }
2093
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002094 hdd_ipa->resource_unloading = true;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002095 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW RX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002096 cdp_ipa_set_active(soc,
2097 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2098 false, false);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002099 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW TX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002100 cdp_ipa_set_active(soc,
2101 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2102 false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002103}
2104
2105/**
2106 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2107 * @context: User context registered with TL (the IPA Global context is
2108 * registered
2109 * @rxpkt: Packet containing the notification
2110 * @staid: ID of the station associated with the packet
2111 *
2112 * Return: None
2113 */
2114static void
2115hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
2116{
2117 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302118 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002119
2120 /*
2121 * When SSR is going on or driver is unloading, just return.
2122 */
2123 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302124 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002125 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002126
2127 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2128 return;
2129
Srinivas Girigowda97852372017-03-06 16:52:59 -08002130 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002131 __func__, event);
2132
2133 switch (event) {
2134 case IPA_RM_RESOURCE_GRANTED:
2135 /* Differed RM Granted */
2136 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302137 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002138 if ((false == hdd_ipa->resource_unloading) &&
2139 (!hdd_ipa->activated_fw_pipe)) {
2140 hdd_ipa_uc_enable_pipes(hdd_ipa);
2141 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302142 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002143 break;
2144
2145 case IPA_RM_RESOURCE_RELEASED:
2146 /* Differed RM Released */
2147 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002148 break;
2149
2150 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302151 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152 "%s, invalid event code %d", __func__, event);
2153 break;
2154 }
2155}
2156
2157/**
2158 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2159 * @hdd_ipa: Global HDD IPA context
2160 * @event: IPA resource manager event to be deferred
2161 *
2162 * This function is called when a resource manager event is received
2163 * from firmware in interrupt context. This function will defer the
2164 * handling to the OL RX thread
2165 *
2166 * Return: None
2167 */
2168static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2169{
2170 enum ipa_rm_event event;
2171 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2172 struct uc_rm_work_struct, work);
2173 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2174 struct hdd_ipa_priv, uc_rm_work);
2175
2176 cds_ssr_protect(__func__);
2177 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002178 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002179 "%s, posted event %d", __func__, event);
2180
2181 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2182 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002183}
2184
2185/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002186 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2187 * @ipa_ctxt: hdd ipa local context
2188 *
2189 * Will handle IPA UC image loaded indication comes from IPA kernel
2190 *
2191 * Return: None
2192 */
2193static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt)
2194{
2195 struct ipa_wdi_out_params pipe_out;
2196
2197 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
2198 if (true == ipa_ctxt->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002199 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002200 __func__);
2201 return;
2202 }
2203
2204 ipa_ctxt->uc_loaded = true;
2205 /* Connect pipe */
2206 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2207 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2208 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
2209 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2210 "%s : TX PIPE Handle %d, DBPA 0x%llx",
2211 __func__, ipa_ctxt->tx_pipe_handle,
2212 (unsigned long long) pipe_out.uc_door_bell_pa);
2213
2214 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2215 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
2216 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2217 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2218 "%s : RX PIPE Handle %d, DBPA 0x%llx",
2219 __func__, ipa_ctxt->rx_pipe_handle,
2220 (unsigned long long) pipe_out.uc_door_bell_pa);
2221
2222 /* If already any STA connected, enable IPA/FW PIPEs */
2223 if (ipa_ctxt->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002224 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002225 "Client already connected, enable IPA/FW PIPEs");
2226 hdd_ipa_uc_handle_first_con(ipa_ctxt);
2227 }
2228}
2229
2230/**
Yun Park637d6482016-10-05 10:51:33 -07002231 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2232 * @hdd_ctx: Global HDD context
2233 * @op_msg: operation message received from firmware
2234 *
2235 * Return: QDF_STATUS enumeration
2236 */
2237#ifdef FEATURE_METERING
2238static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
2239 struct op_msg_type *op_msg)
2240{
2241 struct op_msg_type *msg = op_msg;
2242 struct ipa_uc_sharing_stats *uc_sharing_stats;
2243 struct ipa_uc_quota_rsp *uc_quota_rsp;
2244 struct ipa_uc_quota_ind *uc_quota_ind;
2245 struct hdd_ipa_priv *hdd_ipa;
2246 hdd_adapter_t *adapter;
2247
2248 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2249
2250 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2251 /* fill-up ipa_uc_sharing_stats structure from FW */
2252 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2253 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2254
2255 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2256 sizeof(struct ipa_uc_sharing_stats));
2257
2258 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2259
2260 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2261 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2262 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2263 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2264 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2265 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2266 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2267 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2268 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2269 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2270 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2271 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2272 /* received set quota response */
2273 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2274 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2275
2276 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2277 sizeof(struct ipa_uc_quota_rsp));
2278
2279 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2280 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2281 "%s: success=%d, quota_bytes=%llu",
2282 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2283 hdd_ipa->ipa_quota_rsp.success,
2284 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2285 hdd_ipa->ipa_quota_rsp.quota_lo);
2286 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2287 /* hit quota limit */
2288 uc_quota_ind = (struct ipa_uc_quota_ind *)
2289 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2290
2291 hdd_ipa->ipa_quota_ind.quota_bytes =
2292 uc_quota_ind->quota_bytes;
2293
2294 /* send quota exceeded indication to IPA */
2295 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2296 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2297 hdd_ipa->ipa_quota_ind.quota_bytes);
2298
2299 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2300 if (adapter)
2301 ipa_broadcast_wdi_quota_reach_ind(
2302 adapter->dev->ifindex,
2303 uc_quota_ind->quota_bytes);
2304 else
2305 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2306 "Failed quota_reach_ind: NULL adapter");
2307 } else {
2308 return QDF_STATUS_E_INVAL;
2309 }
2310
2311 return QDF_STATUS_SUCCESS;
2312}
2313#else
2314static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
2315 struct op_msg_type *op_msg)
2316{
2317 return QDF_STATUS_E_INVAL;
2318}
2319#endif
2320
2321/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002322 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2323 * @op_msg: operation message received from firmware
2324 * @usr_ctxt: user context registered with TL (we register the HDD Global
2325 * context)
2326 *
2327 * Return: None
2328 */
2329static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2330{
2331 struct op_msg_type *msg = op_msg;
2332 struct ipa_uc_fw_stats *uc_fw_stat;
2333 struct IpaHwStatsWDIInfoData_t ipa_stat;
2334 struct hdd_ipa_priv *hdd_ipa;
2335 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302336 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002337
2338 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302339 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002340 return;
2341 }
2342
2343 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302344 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002345 "%s, INVALID OPCODE %d", __func__, msg->op_code);
2346 return;
2347 }
2348
2349 hdd_ctx = (hdd_context_t *) usr_ctxt;
2350
2351 /*
2352 * When SSR is going on or driver is unloading, just return.
2353 */
2354 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302355 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302356 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002357 return;
2358 }
2359
2360 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2361
Govind Singhb6a89772016-08-12 11:23:35 +05302362 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002363 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002364
2365 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2366 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302367 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002368 hdd_ipa->activated_fw_pipe++;
2369 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2370 hdd_ipa->resource_loading = false;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002371 if (hdd_ipa->wdi_enabled == false) {
2372 hdd_ipa->wdi_enabled = true;
2373 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2374 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2375 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002376 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002377 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002378 if (hdd_ipa->pending_cons_req)
2379 ipa_rm_notify_completion(
2380 IPA_RM_RESOURCE_GRANTED,
2381 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002382 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002383 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302384 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002385 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002386 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302387 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002388 hdd_ipa->activated_fw_pipe--;
2389 if (!hdd_ipa->activated_fw_pipe) {
2390 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002391 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2392 ipa_rm_release_resource(
2393 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002394 /*
2395 * Sync return success from IPA
2396 * Enable/resume all the PIPEs
2397 */
Yun Park5b635012015-12-02 15:05:01 -08002398 hdd_ipa->resource_unloading = false;
2399 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2400 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002401 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302402 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002403 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002404 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002405 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002406 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302407 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002408 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002409 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002410 "CE RING SIZE: %d\n"
2411 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002412 (unsigned long long)res->ce_sr_base_paddr,
2413 res->ce_sr_ring_size,
2414 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302415 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002416 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002417 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002418 "COMP RING SIZE: %d\n"
2419 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002420 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002421 (unsigned long long)res->tx_comp_ring_base_paddr,
2422 res->tx_comp_ring_size,
2423 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08002424 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302425 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002426 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002427 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002428 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002429 "IND RING DBELL : 0x%llx\n"
2430 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002431 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08002432 "NUM TX FWD OK : %llu\n"
2433 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08002434 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002435 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08002436 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
2437 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002438 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08002439 hdd_ipa->stats.num_tx_fwd_ok,
2440 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302441 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002442 "==== IPA_UC WLAN_HOST CONTROL ====\n"
2443 "SAP NUM STAs: %d\n"
2444 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08002445 "CONCURRENT MODE: %s\n"
2446 "TX PIPE HDL: 0x%x\n"
2447 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002448 "RSC LOADING : %d\n"
2449 "RSC UNLOADING : %d\n"
2450 "PNDNG CNS RQT : %d",
2451 hdd_ipa->sap_num_connected_sta,
2452 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08002453 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002454 hdd_ipa->tx_pipe_handle,
2455 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08002456 hdd_ipa->resource_loading,
2457 hdd_ipa->resource_unloading,
2458 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002459
2460 /* STATs from FW */
2461 uc_fw_stat = (struct ipa_uc_fw_stats *)
2462 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302463 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002464 "==== IPA_UC WLAN_FW TX ====\n"
2465 "COMP RING BASE: 0x%x\n"
2466 "COMP RING SIZE: %d\n"
2467 "COMP RING DBELL : 0x%x\n"
2468 "COMP RING DBELL IND VAL : %d\n"
2469 "COMP RING DBELL CACHED VAL : %d\n"
2470 "COMP RING DBELL CACHED VAL : %d\n"
2471 "PKTS ENQ : %d\n"
2472 "PKTS COMP : %d\n"
2473 "IS SUSPEND : %d\n"
2474 "RSVD : 0x%x",
2475 uc_fw_stat->tx_comp_ring_base,
2476 uc_fw_stat->tx_comp_ring_size,
2477 uc_fw_stat->tx_comp_ring_dbell_addr,
2478 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2479 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2480 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2481 uc_fw_stat->tx_pkts_enqueued,
2482 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002483 uc_fw_stat->tx_is_suspend,
2484 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302485 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002486 "==== IPA_UC WLAN_FW RX ====\n"
2487 "IND RING BASE: 0x%x\n"
2488 "IND RING SIZE: %d\n"
2489 "IND RING DBELL : 0x%x\n"
2490 "IND RING DBELL IND VAL : %d\n"
2491 "IND RING DBELL CACHED VAL : %d\n"
2492 "RDY IND ADDR : 0x%x\n"
2493 "RDY IND CACHE VAL : %d\n"
2494 "RFIL IND : %d\n"
2495 "NUM PKT INDICAT : %d\n"
2496 "BUF REFIL : %d\n"
2497 "NUM DROP NO SPC : %d\n"
2498 "NUM DROP NO BUF : %d\n"
2499 "IS SUSPND : %d\n"
2500 "RSVD : 0x%x\n",
2501 uc_fw_stat->rx_ind_ring_base,
2502 uc_fw_stat->rx_ind_ring_size,
2503 uc_fw_stat->rx_ind_ring_dbell_addr,
2504 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2505 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2506 uc_fw_stat->rx_ind_ring_rdidx_addr,
2507 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2508 uc_fw_stat->rx_refill_idx,
2509 uc_fw_stat->rx_num_pkts_indicated,
2510 uc_fw_stat->rx_buf_refilled,
2511 uc_fw_stat->rx_num_ind_drop_no_space,
2512 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002513 uc_fw_stat->rx_is_suspend,
2514 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002515 /* STATs from IPA */
2516 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302517 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002518 "==== IPA_UC IPA TX ====\n"
2519 "NUM PROCD : %d\n"
2520 "CE DBELL : 0x%x\n"
2521 "NUM DBELL FIRED : %d\n"
2522 "COMP RNG FULL : %d\n"
2523 "COMP RNG EMPT : %d\n"
2524 "COMP RNG USE HGH : %d\n"
2525 "COMP RNG USE LOW : %d\n"
2526 "BAM FIFO FULL : %d\n"
2527 "BAM FIFO EMPT : %d\n"
2528 "BAM FIFO USE HGH : %d\n"
2529 "BAM FIFO USE LOW : %d\n"
2530 "NUM DBELL : %d\n"
2531 "NUM UNEXP DBELL : %d\n"
2532 "NUM BAM INT HDL : 0x%x\n"
2533 "NUM BAM INT NON-RUN : 0x%x\n"
2534 "NUM QMB INT HDL : 0x%x",
2535 ipa_stat.tx_ch_stats.num_pkts_processed,
2536 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2537 ipa_stat.tx_ch_stats.num_db_fired,
2538 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2539 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2540 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2541 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2542 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2543 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2544 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2545 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2546 ipa_stat.tx_ch_stats.num_db,
2547 ipa_stat.tx_ch_stats.num_unexpected_db,
2548 ipa_stat.tx_ch_stats.num_bam_int_handled,
2549 ipa_stat.tx_ch_stats.
2550 num_bam_int_in_non_runnning_state,
2551 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2552
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302553 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002554 "==== IPA_UC IPA RX ====\n"
2555 "MAX OST PKT : %d\n"
2556 "NUM PKT PRCSD : %d\n"
2557 "RNG RP : 0x%x\n"
2558 "COMP RNG FULL : %d\n"
2559 "COMP RNG EMPT : %d\n"
2560 "COMP RNG USE HGH : %d\n"
2561 "COMP RNG USE LOW : %d\n"
2562 "BAM FIFO FULL : %d\n"
2563 "BAM FIFO EMPT : %d\n"
2564 "BAM FIFO USE HGH : %d\n"
2565 "BAM FIFO USE LOW : %d\n"
2566 "NUM DB : %d\n"
2567 "NUM UNEXP DB : %d\n"
2568 "NUM BAM INT HNDL : 0x%x\n",
2569 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2570 ipa_stat.rx_ch_stats.num_pkts_processed,
2571 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2572 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2573 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2574 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2575 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2576 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2577 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2578 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2579 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2580 ipa_stat.rx_ch_stats.num_db,
2581 ipa_stat.rx_ch_stats.num_unexpected_db,
2582 ipa_stat.rx_ch_stats.num_bam_int_handled);
2583 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2584 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2585 /* STATs from FW */
2586 uc_fw_stat = (struct ipa_uc_fw_stats *)
2587 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302588 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002589 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2590 uc_fw_stat->tx_pkts_completed,
2591 hdd_ipa->ipa_p_tx_packets);
2592 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2593 (uc_fw_stat->rx_num_ind_drop_no_space +
2594 uc_fw_stat->rx_num_ind_drop_no_buf +
2595 uc_fw_stat->rx_num_pkts_indicated),
2596 hdd_ipa->ipa_p_rx_packets);
2597
2598 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2599 hdd_ipa->ipa_p_rx_packets =
2600 (uc_fw_stat->rx_num_ind_drop_no_space +
2601 uc_fw_stat->rx_num_ind_drop_no_buf +
2602 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302603 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002604 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2605 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2606 hdd_ipa_uc_loaded_handler(hdd_ipa);
2607 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002608 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2609 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2610 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002611 }
Yun Park8957d802017-01-25 12:27:29 -08002612
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302613 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002614}
2615
2616
2617/**
2618 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2619 * @adapter: device adapter instance
2620 * @offload_type: MCC or SCC
2621 * @enable: TX offload enable or disable
2622 *
2623 * Return: none
2624 */
2625static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002626 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002627{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002628 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002629 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002630 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002631 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002632
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002633 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002634 return;
2635
Yun Park8292dcb2016-10-07 16:46:06 -07002636 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002637 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002638
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002639 if (!iface_context) {
2640 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2641 "Interface context is NULL");
2642 return;
2643 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08002644 if (session_id >= CSR_ROAM_SESSION_MAX) {
2645 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2646 "invalid session id: %d", session_id);
2647 return;
2648 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002649 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002650 /* IPA offload status is already set as desired */
2651 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002652 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
2653 "IPA offload status is already set",
2654 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002655 return;
2656 }
2657
Yun Park4540e862016-11-10 16:30:06 -08002658 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2659 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2660 "invalid session id: %d, offload_type=%d, enable=%d",
2661 adapter->sessionId, offload_type, enable);
2662 return;
2663 }
2664
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302665 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002666 sizeof(ipa_offload_enable_disable));
2667 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002668 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002669 ipa_offload_enable_disable.enable = enable;
2670
Srinivas Girigowda97852372017-03-06 16:52:59 -08002671 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park8292dcb2016-10-07 16:46:06 -07002672 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002673 ipa_offload_enable_disable.offload_type,
2674 ipa_offload_enable_disable.vdev_id,
2675 ipa_offload_enable_disable.enable);
2676
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302677 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002678 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2679 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302680 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002681 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2682 __func__,
2683 ipa_offload_enable_disable.offload_type,
2684 ipa_offload_enable_disable.vdev_id,
2685 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002686 } else {
2687 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002688 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002689 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002690 }
2691}
2692
2693/**
2694 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2695 * @work: uC OP work
2696 *
2697 * Return: None
2698 */
2699static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2700{
2701 struct op_msg_type *msg;
2702 struct uc_op_work_struct *uc_op_work = container_of(work,
2703 struct uc_op_work_struct, work);
2704 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2705
2706 cds_ssr_protect(__func__);
2707
2708 msg = uc_op_work->msg;
2709 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002710 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002711 "%s, posted msg %d", __func__, msg->op_code);
2712
2713 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2714
2715 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002716}
2717
2718/**
2719 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2720 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2721 * @op_msg: operation message received from firmware
2722 * @hdd_ctx: Global HDD context
2723 *
2724 * Return: None
2725 */
2726static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2727{
2728 struct hdd_ipa_priv *hdd_ipa;
2729 struct op_msg_type *msg;
2730 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302731 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732
2733 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302734 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002735 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002736
2737 msg = (struct op_msg_type *)op_msg;
2738 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2739
2740 if (unlikely(!hdd_ipa))
2741 goto end;
2742
2743 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302744 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002745 __func__, msg->op_code);
2746 goto end;
2747 }
2748
2749 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2750 if (uc_op_work->msg)
2751 /* When the same uC OPCODE is already pended, just return */
2752 goto end;
2753
2754 uc_op_work->msg = msg;
2755 schedule_work(&uc_op_work->work);
2756 return;
2757
2758end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302759 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002760}
2761
2762/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002763 * hdd_ipa_init_uc_op_work - init ipa uc op work
2764 * @work: struct work_struct
2765 * @work_handler: work_handler
2766 *
2767 * Return: none
2768 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002769static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002770 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002771{
2772 INIT_WORK(work, work_handler);
2773}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002774
Yun Park637d6482016-10-05 10:51:33 -07002775#ifdef FEATURE_METERING
2776/**
2777 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2778 * IPA calls to get WLAN stats or set quota limit.
2779 * @priv: pointer to private data registered with IPA (we register a
2780 *» pointer to the global IPA context)
2781 * @evt: the IPA event which triggered the callback
2782 * @data: data associated with the event
2783 *
2784 * Return: None
2785 */
2786static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2787 void *data)
2788{
2789 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2790 hdd_adapter_t *adapter = NULL;
2791 struct ipa_get_wdi_sap_stats *wdi_sap_stats;
2792 struct ipa_set_wifi_quota *ipa_set_quota;
2793 int ret = 0;
2794
2795 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2796 return;
2797
2798 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2799
2800 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2801
2802 switch (evt) {
2803 case IPA_GET_WDI_SAP_STATS:
2804 /* fill-up ipa_get_wdi_sap_stats structure after getting
2805 ipa_uc_fw_stats from FW */
2806 wdi_sap_stats = data;
2807
2808 if (!adapter) {
2809 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2810 "IPA uC share stats failed - no adapter");
2811 wdi_sap_stats->stats_valid = 0;
2812 return;
2813 }
2814
2815 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
2816 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
2817 hdd_ipa_uc_sharing_stats_request(adapter,
2818 wdi_sap_stats->reset_stats);
2819 ret = wait_for_completion_timeout(
2820 &hdd_ipa->ipa_uc_sharing_stats_comp,
2821 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2822 if (!ret) {
2823 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2824 "IPA uC share stats request timed out");
2825 wdi_sap_stats->stats_valid = 0;
2826 } else {
2827 wdi_sap_stats->stats_valid = 1;
2828
2829 wdi_sap_stats->ipv4_rx_packets =
2830 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2831 wdi_sap_stats->ipv4_rx_bytes =
2832 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2833 wdi_sap_stats->ipv6_rx_packets =
2834 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2835 wdi_sap_stats->ipv6_rx_bytes =
2836 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
2837 wdi_sap_stats->ipv4_tx_packets =
2838 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
2839 wdi_sap_stats->ipv4_tx_bytes =
2840 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
2841 wdi_sap_stats->ipv6_tx_packets =
2842 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
2843 wdi_sap_stats->ipv6_tx_bytes =
2844 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
2845 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2846 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2847 "IPA_GET_WDI_SAP_STATS",
2848 wdi_sap_stats->stats_valid,
2849 wdi_sap_stats->ipv4_rx_packets,
2850 wdi_sap_stats->ipv4_rx_bytes,
2851 wdi_sap_stats->ipv6_rx_packets,
2852 wdi_sap_stats->ipv6_rx_bytes,
2853 wdi_sap_stats->ipv4_tx_packets,
2854 wdi_sap_stats->ipv4_tx_bytes,
2855 wdi_sap_stats->ipv6_tx_packets,
2856 wdi_sap_stats->ipv6_tx_bytes);
2857 }
2858 break;
2859 case IPA_SET_WIFI_QUOTA:
2860 /* get ipa_set_wifi_quota structure from IPA and pass to FW
2861 through quota_exceeded field in ipa_uc_fw_stats */
2862 ipa_set_quota = data;
2863
2864 if (!adapter) {
2865 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2866 "IPA uC set quota failed - no adapter");
2867 ipa_set_quota->set_valid = 0;
2868 return;
2869 }
2870
2871 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
2872 ipa_set_quota->quota_bytes);
2873
2874 ret = wait_for_completion_timeout(
2875 &hdd_ipa->ipa_uc_set_quota_comp,
2876 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
2877 if (!ret) {
2878 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2879 "IPA uC set quota request timed out");
2880 ipa_set_quota->set_valid = 0;
2881 } else {
2882 ipa_set_quota->quota_bytes =
2883 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
2884 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
2885 ipa_set_quota->set_valid =
2886 hdd_ipa->ipa_quota_rsp.success;
2887 }
2888
2889 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
2890 ipa_set_quota->quota_bytes,
2891 ipa_set_quota->set_valid);
2892 break;
2893 }
2894}
2895
2896/**
2897 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2898 * IPA calls to get WLAN stats or set quota limit.
2899 * @priv: pointer to private data registered with IPA (we register a
2900 *» pointer to the global IPA context)
2901 * @evt: the IPA event which triggered the callback
2902 * @data: data associated with the event
2903 *
2904 * Return: None
2905 */
2906static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2907 void *data)
2908{
2909 cds_ssr_protect(__func__);
2910 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
2911 cds_ssr_unprotect(__func__);
2912}
2913
2914static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt,
2915 struct ipa_wdi_in_params *pipe_in)
2916{
2917 pipe_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb;
2918
2919 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
2920 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
2921}
2922#else
2923static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt,
2924 struct ipa_wdi_in_params *pipe_in)
2925{
2926}
2927#endif
2928
Rajeev Kumar217f2172016-01-06 18:11:55 -08002929/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002930 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2931 * @hdd_ctx: Global HDD context
2932 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002933 * This function is called to update IPA pipe configuration with resources
2934 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
2935 * (cds_enable)
2936 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302937 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002938 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002939QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002940{
2941 struct ipa_wdi_in_params pipe_in;
2942 struct ipa_wdi_out_params pipe_out;
2943 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07002944 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002945 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2946 int ret;
2947 QDF_STATUS stat = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002948
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002949 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2950 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002951
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002952 ENTER();
2953 /* Do only IPA Pipe specific configuration here. All one time
2954 * initialization wrt IPA UC shall in hdd_ipa_init and those need
2955 * to be reinit at SSR shall in be SSR deinit / reinit functions.
2956 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002957 if (!pdev || !soc) {
2958 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkbaa62862017-01-18 13:43:34 -08002959 stat = QDF_STATUS_E_FAILURE;
2960 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002961 }
Yun Parkbaa62862017-01-18 13:43:34 -08002962
2963 cdp_ipa_get_resource(soc, (void *)pdev, &ipa_ctxt->ipa_resource);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002964 if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) ||
2965 (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2966 (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2967 (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2968 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2969 "IPA UC resource alloc fail");
2970 return QDF_STATUS_E_FAILURE;
2971 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002972 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2973 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302974 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2975 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002976
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002977 /* TX PIPE */
2978 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2979 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2980 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2981 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2982 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2983 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2984 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2985 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2986 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2987 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2988 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2989 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2990 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002991 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2992 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002993 pipe_in.sys.keep_ipa_awake = true;
2994 }
2995
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002996 pipe_in.u.dl.comp_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002997 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Yun Park034e9782017-01-23 16:17:11 -08002998 /* IPA requires total byte counts of Tx comp ring */
Leo Chang3bc8fed2015-11-13 10:59:47 -08002999 pipe_in.u.dl.comp_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003000 ipa_ctxt->ipa_resource.tx_comp_ring_size *
3001 sizeof(qdf_dma_addr_t);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003002 pipe_in.u.dl.ce_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003003 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003004 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
3005 pipe_in.u.dl.ce_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003006 ipa_ctxt->ipa_resource.ce_sr_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003007 pipe_in.u.dl.num_tx_buffers =
Yun Parkbaa62862017-01-18 13:43:34 -08003008 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003009
Yun Parkbaa62862017-01-18 13:43:34 -08003010 qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in,
3011 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003012 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08003013 IPA_CLIENT_WLAN1_CONS);
3014
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003015 if (true == ipa_ctxt->uc_loaded) {
3016 /* Connect WDI IPA PIPE */
Yun Parkbaa62862017-01-18 13:43:34 -08003017 ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
3018 if (ret) {
3019 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3020 "ipa_connect_wdi_pipe falied for Tx: ret=%d",
3021 ret);
3022 stat = QDF_STATUS_E_FAILURE;
3023 goto fail_return;
3024 }
Yun Park637d6482016-10-05 10:51:33 -07003025
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003026 /* Micro Controller Doorbell register */
Srinivas Girigowda97852372017-03-06 16:52:59 -08003027 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003028 "CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
3029 (unsigned int)pipe_out.uc_door_bell_pa,
3030 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003031 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Yun Parkbaa62862017-01-18 13:43:34 -08003032
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003033 /* WLAN TX PIPE Handle */
3034 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08003035 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003036 "TX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x, %s %d, %s %d, %s 0x%x",
3037 "comp_ring_base_pa",
3038 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
3039 "comp_ring_size",
3040 pipe_in.u.dl.comp_ring_size,
3041 "ce_ring_base_pa",
3042 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
3043 "ce_door_bell_pa",
3044 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
3045 "ce_ring_size",
3046 pipe_in.u.dl.ce_ring_size,
3047 "num_tx_buffers",
3048 pipe_in.u.dl.num_tx_buffers,
3049 "tx_comp_doorbell_paddr",
3050 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003051 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003052
3053 /* RX PIPE */
3054 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3055 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
3056 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
3057 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
3058 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
3059 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
3060 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
3061 sizeof(struct sps_iovec);
3062 pipe_in.sys.notify = hdd_ipa_w2i_cb;
3063 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303064 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkbaa62862017-01-18 13:43:34 -08003065 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003066 pipe_in.sys.keep_ipa_awake = true;
3067 }
3068
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003069 pipe_in.u.ul.rdy_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003070 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003071 pipe_in.u.ul.rdy_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003072 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003073 pipe_in.u.ul.rdy_ring_rp_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003074 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003075 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Yun Parkbaa62862017-01-18 13:43:34 -08003076
Yun Park637d6482016-10-05 10:51:33 -07003077 hdd_ipa_init_metering(ipa_ctxt, &pipe_in);
3078
Yun Parkbaa62862017-01-18 13:43:34 -08003079 qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in,
3080 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003081 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08003082 IPA_CLIENT_WLAN1_PROD);
3083
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003084 if (true == ipa_ctxt->uc_loaded) {
Yun Parkbaa62862017-01-18 13:43:34 -08003085 ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
3086 if (ret) {
3087 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3088 "ipa_connect_wdi_pipe falied for Rx: ret=%d",
3089 ret);
3090 stat = QDF_STATUS_E_FAILURE;
3091 goto fail_return;
3092
3093 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003094 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
3095 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08003096 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08003097 "PROD DB pipe out 0x%x TX PIPE Handle 0x%x",
3098 (unsigned int)pipe_out.uc_door_bell_pa,
3099 ipa_ctxt->tx_pipe_handle);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003100 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003101 "RX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x",
3102 "rdy_ring_base_pa",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003103 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
Yun Park637d6482016-10-05 10:51:33 -07003104 "rdy_ring_size",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003105 pipe_in.u.ul.rdy_ring_size,
Yun Park637d6482016-10-05 10:51:33 -07003106 "rdy_ring_rp_pa",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003107 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
Yun Park637d6482016-10-05 10:51:33 -07003108 "rx_ready_doorbell_paddr",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003109 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
3110 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003111
Yun Parkbaa62862017-01-18 13:43:34 -08003112 cdp_ipa_set_doorbell_paddr(soc, (void *)pdev,
3113 ipa_ctxt->tx_comp_doorbell_paddr,
3114 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003115
Yun Parkbaa62862017-01-18 13:43:34 -08003116 cdp_ipa_register_op_cb(soc, (void *)pdev,
3117 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
3118
3119 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
3120 "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x",
3121 pdev->ipa_uc_op_cb,
3122 (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr,
3123 (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003124
Yun Parkbaa62862017-01-18 13:43:34 -08003125fail_return:
3126 EXIT();
3127 return stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003128}
3129
Leo Change3e49442015-10-26 20:07:13 -07003130/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303131 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
3132 * @hdd_ctx: Global HDD context
3133 *
3134 * Return: 0 on success, negativer errno on error
3135 */
3136int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx)
3137{
3138 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
3139 int ret = 0;
3140
3141 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3142 return ret;
3143
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05303144 if (!hdd_ipa->ipa_pipes_down)
3145 hdd_ipa_uc_disable_pipes(hdd_ipa);
3146
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303147 if (true == hdd_ipa->uc_loaded) {
3148 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
3149 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
3150 __func__, hdd_ipa->tx_pipe_handle);
3151 ret = ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
3152 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
3153 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
3154 __func__, hdd_ipa->rx_pipe_handle);
3155 ret = ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
3156 }
3157
3158 return ret;
3159}
3160
3161/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003162 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07003163 * @hdd_ctx: hdd main context
3164 *
3165 * Force shutdown IPA pipe
3166 * Independent of FW pipe status, IPA pipe shutdonw progress
3167 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3168 * independent from FW pipe status
3169 *
3170 * Return: NONE
3171 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003172static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07003173{
3174 struct hdd_ipa_priv *hdd_ipa;
3175
3176 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
3177 return;
3178
3179 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
3180 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303181 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07003182 "IPA pipes are not down yet, force shutdown");
3183 hdd_ipa_uc_disable_pipes(hdd_ipa);
3184 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003185 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Leo Change3e49442015-10-26 20:07:13 -07003186 "IPA pipes are down, do nothing");
3187 }
Leo Change3e49442015-10-26 20:07:13 -07003188}
3189
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003190/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003191 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
3192 * __hdd_ipa_uc_force_pipe_shutdown
3193 * @hdd_ctx: hdd main context
3194 *
3195 * Force shutdown IPA pipe
3196 * Independent of FW pipe status, IPA pipe shutdonw progress
3197 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3198 * independent from FW pipe status
3199 *
3200 * Return: NONE
3201 */
3202void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
3203{
3204 cds_ssr_protect(__func__);
3205 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
3206 cds_ssr_unprotect(__func__);
3207}
3208
3209/**
Govind Singh9c58eba2016-09-02 16:23:06 +05303210 * hdd_ipa_msg_free_fn() - Free an IPA message
3211 * @buff: pointer to the IPA message
3212 * @len: length of the IPA message
3213 * @type: type of IPA message
3214 *
3215 * Return: None
3216 */
3217static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
3218{
Srinivas Girigowda97852372017-03-06 16:52:59 -08003219 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05303220 ghdd_ipa->stats.num_free_msg++;
3221 qdf_mem_free(buff);
3222}
3223
Govind Singh9c58eba2016-09-02 16:23:06 +05303224/**
jge62037862016-12-09 10:44:33 +08003225 * hdd_ipa_uc_send_evt() - send event to ipa
3226 * @hdd_ctx: pointer to hdd context
3227 * @type: event type
3228 * @mac_addr: pointer to mac address
3229 *
3230 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303231 *
3232 * Return: 0 - Success
3233 */
jge62037862016-12-09 10:44:33 +08003234static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
3235 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303236{
jge62037862016-12-09 10:44:33 +08003237 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05303238 struct ipa_msg_meta meta;
3239 struct ipa_wlan_msg *msg;
3240 int ret = 0;
jge62037862016-12-09 10:44:33 +08003241
3242 meta.msg_len = sizeof(struct ipa_wlan_msg);
3243 msg = qdf_mem_malloc(meta.msg_len);
3244 if (msg == NULL) {
3245 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3246 "msg allocation failed");
3247 return -ENOMEM;
3248 }
3249
3250 meta.msg_type = type;
3251 strlcpy(msg->name, adapter->dev->name,
3252 IPA_RESOURCE_NAME_MAX);
3253 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003254 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
jge62037862016-12-09 10:44:33 +08003255 msg->name, meta.msg_type);
3256 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
3257 if (ret) {
3258 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3259 "%s: Evt: %d fail:%d",
3260 msg->name, meta.msg_type, ret);
3261 qdf_mem_free(msg);
3262 return ret;
3263 }
3264
3265 hdd_ipa->stats.num_send_msg++;
3266
3267 return ret;
3268}
3269
3270/**
3271 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3272 * @hdd_ctx: pointer to hdd adapter
3273 *
3274 * Send disconnect client event to IPA driver during SSR
3275 *
3276 * Return: 0 - Success
3277 */
3278static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
3279{
3280 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3281 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303282 int i;
3283
3284 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
3285 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
3286 continue;
3287 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08003288 (!adapter->aStaInfo[i].isDeauthInProgress) &&
3289 hdd_ipa->sap_num_connected_sta) {
3290 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
3291 adapter->aStaInfo[i].macAddrSTA.bytes);
3292 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303293 }
3294 }
3295
3296 return ret;
3297}
3298
3299/**
jge62037862016-12-09 10:44:33 +08003300 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3301 * @hdd_ctx: pointer to hdd adapter
3302 *
3303 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303304 *
3305 * Return: 0 - Success
3306 */
jge62037862016-12-09 10:44:33 +08003307
3308static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
3309{
3310 int ret = 0;
3311
3312 if (adapter->ipa_context)
3313 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3314 adapter->dev->dev_addr);
3315
3316 return ret;
3317}
3318
jge62037862016-12-09 10:44:33 +08003319/**
3320 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3321 * @hdd_ctx: pointer to hdd adapter
3322 *
3323 * Send disconnect sta event to IPA driver during SSR
3324 *
3325 * Return: 0 - Success
3326 */
3327static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
3328{
3329 hdd_station_ctx_t *pHddStaCtx;
3330 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3331 int ret = 0;
3332
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003333 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003334 hdd_ipa->sta_connected) {
3335 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
3336 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003337 pHddStaCtx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003338 }
3339
3340 return ret;
3341}
jge62037862016-12-09 10:44:33 +08003342
3343/**
3344 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3345 * @hdd_ctx: pointer to hdd context
3346 *
3347 * Send disconnect event to IPA driver during SSR
3348 *
3349 * Return: 0 - Success
3350 */
3351static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303352{
3353 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
3354 QDF_STATUS status;
3355 hdd_adapter_t *adapter;
3356 int ret = 0;
3357
Govind Singh9c58eba2016-09-02 16:23:06 +05303358 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
3359 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
3360 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08003361 if (adapter->device_mode == QDF_SAP_MODE) {
3362 hdd_ipa_uc_disconnect_client(adapter);
3363 hdd_ipa_uc_disconnect_ap(adapter);
3364 } else if (adapter->device_mode == QDF_STA_MODE) {
3365 hdd_ipa_uc_disconnect_sta(adapter);
3366 }
3367
Govind Singh9c58eba2016-09-02 16:23:06 +05303368 status = hdd_get_next_adapter(
3369 hdd_ctx, adapter_node, &next);
3370 adapter_node = next;
3371 }
3372
3373 return ret;
3374}
3375
3376/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003377 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003378 *
3379 * Deinit basic IPA UC host side to be in sync reloaded FW during
3380 * SSR
3381 *
3382 * Return: 0 - Success
3383 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003384static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003385{
3386 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3387 int idx;
3388 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303389 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003390
Arun Khandavallicc544b32017-01-30 19:52:16 +05303391 if (!hdd_ipa)
3392 return 0;
3393
3394 hdd_ctx = hdd_ipa->hdd_ctx;
3395 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003396 return 0;
3397
jge62037862016-12-09 10:44:33 +08003398 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303399 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003400
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003401 /* Clean up HDD IPA interfaces */
3402 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3403 (idx < HDD_IPA_MAX_IFACE); idx++) {
3404 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003405 if (iface_context->adapter && iface_context->adapter->magic ==
3406 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003407 hdd_ipa_cleanup_iface(iface_context);
3408 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003409 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410 /* After SSR, wlan driver reloads FW again. But we need to protect
3411 * IPA submodule during SSR transient state. So deinit basic IPA
3412 * UC host side to be in sync with reloaded FW during SSR
3413 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003414
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303415 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003416 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3417 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3418 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3419 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303420 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421
Guolei Bianca144d82016-11-10 11:07:42 +08003422 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3423 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3424
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003425 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
3426 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
3427 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
3428 hdd_ipa->uc_op_work[idx].msg = NULL;
3429 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003430 return 0;
3431}
3432
3433/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003434 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3435 *
3436 * Deinit basic IPA UC host side to be in sync reloaded FW during
3437 * SSR
3438 *
3439 * Return: 0 - Success
3440 */
3441int hdd_ipa_uc_ssr_deinit(void)
3442{
3443 int ret;
3444
3445 cds_ssr_protect(__func__);
3446 ret = __hdd_ipa_uc_ssr_deinit();
3447 cds_ssr_unprotect(__func__);
3448
3449 return ret;
3450}
3451
3452/**
3453 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003454 *
3455 * Init basic IPA UC host side to be in sync with reloaded FW after
3456 * SSR to resume IPA UC operations
3457 *
3458 * Return: 0 - Success
3459 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303460static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003461{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003462
Arun Khandavallicc544b32017-01-30 19:52:16 +05303463 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3464 int i;
3465 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303466
3467 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3468 return 0;
3469
Arun Khandavallicc544b32017-01-30 19:52:16 +05303470 /* Create the interface context */
3471 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3472 iface_context = &hdd_ipa->iface_context[i];
3473 iface_context->hdd_ipa = hdd_ipa;
3474 iface_context->cons_client =
3475 hdd_ipa_adapter_2_client[i].cons_client;
3476 iface_context->prod_client =
3477 hdd_ipa_adapter_2_client[i].prod_client;
3478 iface_context->iface_id = i;
3479 iface_context->adapter = NULL;
3480 }
3481 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3482 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3483 hdd_ipa->vdev_offload_enabled[i] = false;
3484 }
3485
3486 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3487 hdd_ipa->resource_loading = false;
3488 hdd_ipa->resource_unloading = false;
3489 hdd_ipa->sta_connected = 0;
3490 hdd_ipa->ipa_pipes_down = true;
3491 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303492 }
3493
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003494 return 0;
3495}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003496
3497/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003498 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3499 *
3500 * Init basic IPA UC host side to be in sync with reloaded FW after
3501 * SSR to resume IPA UC operations
3502 *
3503 * Return: 0 - Success
3504 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303505int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003506{
3507 int ret;
3508
3509 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303510 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003511 cds_ssr_unprotect(__func__);
3512
3513 return ret;
3514}
3515
3516/**
3517 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08003518 * @hdd_ctx: Global HDD context
3519 * @skb: skb sent to IPA
3520 * @session_id: send packet instance session id
3521 *
3522 * Send TX packet which generated by system to IPA.
3523 * This routine only will be used for function verification
3524 *
3525 * Return: NULL packet sent to IPA properly
3526 * NULL invalid packet drop
3527 * skb packet not sent to IPA. legacy data path should handle
3528 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003529static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08003530 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07003531{
Leo Chang3bc8fed2015-11-13 10:59:47 -08003532 struct ipa_header *ipa_header;
3533 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003534 struct hdd_ipa_priv *hdd_ipa;
3535
3536 if (wlan_hdd_validate_context(hdd_ctx))
3537 return skb;
3538
3539 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003540
3541 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3542 return skb;
3543
Leo Chang07b28f62016-05-11 12:29:22 -07003544 if (!hdd_ipa)
3545 return skb;
3546
3547 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
3548 return skb;
3549
Leo Changcc923e22016-06-16 15:29:03 -07003550 if (skb_headroom(skb) <
3551 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07003552 return skb;
3553
Leo Chang3bc8fed2015-11-13 10:59:47 -08003554 ipa_header = (struct ipa_header *) skb_push(skb,
3555 sizeof(struct ipa_header));
3556 if (!ipa_header) {
3557 /* No headroom, legacy */
3558 return skb;
3559 }
3560 memset(ipa_header, 0, sizeof(*ipa_header));
3561 ipa_header->vdev_id = 0;
3562
3563 frag_header = (struct frag_header *) skb_push(skb,
3564 sizeof(struct frag_header));
3565 if (!frag_header) {
3566 /* No headroom, drop */
3567 kfree_skb(skb);
3568 return NULL;
3569 }
3570 memset(frag_header, 0, sizeof(*frag_header));
3571 frag_header->length = skb->len - sizeof(struct frag_header)
3572 - sizeof(struct ipa_header);
3573
3574 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
3575 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07003576}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003577
3578/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003579 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
3580 * @hdd_ctx: Global HDD context
3581 * @skb: skb sent to IPA
3582 * @session_id: send packet instance session id
3583 *
3584 * Send TX packet which generated by system to IPA.
3585 * This routine only will be used for function verification
3586 *
3587 * Return: NULL packet sent to IPA properly
3588 * NULL invalid packet drop
3589 * skb packet not sent to IPA. legacy data path should handle
3590 */
3591struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
3592 struct sk_buff *skb, uint8_t session_id)
3593{
3594 struct sk_buff *ret;
3595
3596 cds_ssr_protect(__func__);
3597 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
3598 cds_ssr_unprotect(__func__);
3599
3600 return ret;
3601}
3602
3603/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003604 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3605 * @work: scheduled work
3606 *
3607 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3608 * not want to immediately release the wake lock since the system
3609 * would then potentially try to suspend when there is a healthy data
3610 * rate. Deferred work is scheduled and this function handles the
3611 * work. When this function is called, if the IPA resource is still
3612 * released then we release the wake lock.
3613 *
3614 * Return: None
3615 */
3616static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3617{
3618 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3619 struct hdd_ipa_priv,
3620 wake_lock_work);
3621
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303622 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003623
3624 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3625 goto end;
3626
3627 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303628 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003629 WIFI_POWER_EVENT_WAKELOCK_IPA);
3630
3631end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303632 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003633}
3634
3635/**
3636 * hdd_ipa_rm_request() - Request resource from IPA
3637 * @hdd_ipa: Global HDD IPA context
3638 *
3639 * Return: 0 on success, negative errno on error
3640 */
3641static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3642{
3643 int ret = 0;
3644
3645 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3646 return 0;
3647
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303648 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003649
3650 switch (hdd_ipa->rm_state) {
3651 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303652 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003653 return 0;
3654 case HDD_IPA_RM_GRANT_PENDING:
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 -EINPROGRESS;
3657 case HDD_IPA_RM_RELEASED:
3658 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3659 break;
3660 }
3661
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303662 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003663
3664 ret = ipa_rm_inactivity_timer_request_resource(
3665 IPA_RM_RESOURCE_WLAN_PROD);
3666
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303667 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003668 if (ret == 0) {
3669 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3670 hdd_ipa->stats.num_rm_grant_imm++;
3671 }
3672
3673 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3674 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303675 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003676 WIFI_POWER_EVENT_WAKELOCK_IPA);
3677 hdd_ipa->wake_lock_released = false;
3678 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303679 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003680
3681 return ret;
3682}
3683
3684/**
3685 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3686 * @hdd_ipa: Global HDD IPA context
3687 *
3688 * Return: 0 if resources released, negative errno otherwise
3689 */
3690static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3691{
3692 int ret = 0;
3693
3694 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3695 return 0;
3696
3697 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3698 return -EAGAIN;
3699
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303700 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003701
Nirav Shahcbc6d722016-03-01 16:24:53 +05303702 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303703 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003704 return -EAGAIN;
3705 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303706 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303708 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003709 switch (hdd_ipa->rm_state) {
3710 case HDD_IPA_RM_GRANTED:
3711 break;
3712 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303713 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003714 return -EINPROGRESS;
3715 case HDD_IPA_RM_RELEASED:
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 0;
3718 }
3719
3720 /* IPA driver returns immediately so set the state here to avoid any
3721 * race condition.
3722 */
3723 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3724 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303725 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003726
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003727 ret = ipa_rm_inactivity_timer_release_resource(
3728 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003729
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303730 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731 if (unlikely(ret != 0)) {
3732 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3733 WARN_ON(1);
3734 }
3735
3736 /*
3737 * If wake_lock is released immediately, kernel would try to suspend
3738 * immediately as well, Just avoid ping-pong between suspend-resume
3739 * while there is healthy amount of data transfer going on by
3740 * releasing the wake_lock after some delay.
3741 */
3742 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3743 msecs_to_jiffies
3744 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3745
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303746 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003747
3748 return ret;
3749}
3750
3751/**
3752 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3753 * @user_data: user data registered with IPA
3754 * @event: the IPA resource manager event that occurred
3755 * @data: the data associated with the event
3756 *
3757 * Return: None
3758 */
3759static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3760 unsigned long data)
3761{
3762 struct hdd_ipa_priv *hdd_ipa = user_data;
3763
3764 if (unlikely(!hdd_ipa))
3765 return;
3766
3767 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3768 return;
3769
Srinivas Girigowda97852372017-03-06 16:52:59 -08003770 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003771
3772 switch (event) {
3773 case IPA_RM_RESOURCE_GRANTED:
3774 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3775 /* RM Notification comes with ISR context
3776 * it should be serialized into work queue to avoid
3777 * ISR sleep problem
3778 */
3779 hdd_ipa->uc_rm_work.event = event;
3780 schedule_work(&hdd_ipa->uc_rm_work.work);
3781 break;
3782 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303783 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003784 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303785 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003786 hdd_ipa->stats.num_rm_grant++;
3787 break;
3788
3789 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003790 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791 hdd_ipa->resource_unloading = false;
3792 break;
3793
3794 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303795 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003796 break;
3797 }
3798}
3799
3800/**
3801 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3802 *
3803 * Callback function registered with IPA that is called when IPA wants
3804 * to release the WLAN consumer resource
3805 *
3806 * Return: 0 if the request is granted, negative errno otherwise
3807 */
3808static int hdd_ipa_rm_cons_release(void)
3809{
3810 return 0;
3811}
3812
3813/**
3814 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3815 *
3816 * Callback function registered with IPA that is called when IPA wants
3817 * to access the WLAN consumer resource
3818 *
3819 * Return: 0 if the request is granted, negative errno otherwise
3820 */
3821static int hdd_ipa_rm_cons_request(void)
3822{
Yun Park4d8b60a2015-10-22 13:59:32 -07003823 int ret = 0;
3824
3825 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303826 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003827 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003828 __func__);
3829 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003830 ret = -EINPROGRESS;
3831 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303832 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003833 "%s: IPA resource unloading in progress",
3834 __func__);
3835 ghdd_ipa->pending_cons_req = true;
3836 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003837 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003838
3839 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003840}
3841
3842/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003843 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003844 * @hdd_ctx: Global HDD context
3845 * @tx_packets: Number of packets transmitted in the last sample period
3846 * @rx_packets: Number of packets received in the last sample period
3847 *
3848 * Return: 0 on success, negative errno on error
3849 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003850static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003851 uint64_t rx_packets)
3852{
3853 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003854 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003855 struct ipa_rm_perf_profile profile;
3856 int ret;
3857
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003858 if (wlan_hdd_validate_context(hdd_ctx))
3859 return 0;
3860
3861 hdd_ipa = hdd_ctx->hdd_ipa;
3862
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003863 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3864 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3865 return 0;
3866
3867 memset(&profile, 0, sizeof(profile));
3868
3869 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3870 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3871 else if (tx_packets >
3872 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3873 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3874 else
3875 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3876
3877 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3878 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3879 else if (rx_packets >
3880 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3881 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3882 else
3883 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3884
Yun Parkec845302016-12-15 09:22:57 -08003885 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003886 "CONS perf curr: %d, next: %d",
3887 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003888 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003889 "PROD perf curr: %d, next: %d",
3890 hdd_ipa->curr_prod_bw, next_prod_bw);
3891
3892 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003893 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003894 hdd_ipa->curr_cons_bw, next_cons_bw);
3895 profile.max_supported_bandwidth_mbps = next_cons_bw;
3896 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3897 &profile);
3898 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003899 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003900
3901 return ret;
3902 }
3903 hdd_ipa->curr_cons_bw = next_cons_bw;
3904 hdd_ipa->stats.num_cons_perf_req++;
3905 }
3906
3907 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003908 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003909 hdd_ipa->curr_prod_bw, next_prod_bw);
3910 profile.max_supported_bandwidth_mbps = next_prod_bw;
3911 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3912 &profile);
3913 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003914 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003915 return ret;
3916 }
3917 hdd_ipa->curr_prod_bw = next_prod_bw;
3918 hdd_ipa->stats.num_prod_perf_req++;
3919 }
3920
3921 return 0;
3922}
3923
3924/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003925 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3926 * @hdd_ctx: Global HDD context
3927 * @tx_packets: Number of packets transmitted in the last sample period
3928 * @rx_packets: Number of packets received in the last sample period
3929 *
3930 * Return: 0 on success, negative errno on error
3931 */
3932int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3933 uint64_t rx_packets)
3934{
3935 int ret;
3936
3937 cds_ssr_protect(__func__);
3938 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3939 cds_ssr_unprotect(__func__);
3940
3941 return ret;
3942}
3943
3944/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003945 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3946 * @work: struct work_struct
3947 * @work_handler: work_handler
3948 *
3949 * Return: none
3950 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003951static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3952 work_func_t work_handler)
3953{
3954 INIT_WORK(work, work_handler);
3955}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003956
3957/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003958 * hdd_ipa_setup_rm() - Setup IPA resource management
3959 * @hdd_ipa: Global HDD IPA context
3960 *
3961 * Return: 0 on success, negative errno on error
3962 */
3963static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3964{
3965 struct ipa_rm_create_params create_params = { 0 };
3966 int ret;
3967
3968 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3969 return 0;
3970
Rajeev Kumar217f2172016-01-06 18:11:55 -08003971 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3972 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003973 memset(&create_params, 0, sizeof(create_params));
3974 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3975 create_params.reg_params.user_data = hdd_ipa;
3976 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3977 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3978
3979 ret = ipa_rm_create_resource(&create_params);
3980 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303981 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982 "Create RM resource failed: %d", ret);
3983 goto setup_rm_fail;
3984 }
3985
3986 memset(&create_params, 0, sizeof(create_params));
3987 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3988 create_params.request_resource = hdd_ipa_rm_cons_request;
3989 create_params.release_resource = hdd_ipa_rm_cons_release;
3990 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3991
3992 ret = ipa_rm_create_resource(&create_params);
3993 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303994 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003995 "Create RM CONS resource failed: %d", ret);
3996 goto delete_prod;
3997 }
3998
3999 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
4000 IPA_RM_RESOURCE_APPS_CONS);
4001
4002 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
4003 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
4004 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304005 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004006 ret);
4007 goto timer_init_failed;
4008 }
4009
4010 /* Set the lowest bandwidth to start with */
4011 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
4012
4013 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304014 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004015 "Set perf level failed: %d", ret);
4016 goto set_perf_failed;
4017 }
4018
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304019 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004020 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
4021 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304022 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004023 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
4024 hdd_ipa->wake_lock_released = true;
4025 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
4026
4027 return ret;
4028
4029set_perf_failed:
4030 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4031
4032timer_init_failed:
4033 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4034
4035delete_prod:
4036 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4037
4038setup_rm_fail:
4039 return ret;
4040}
4041
4042/**
4043 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
4044 * @hdd_ipa: Global HDD IPA context
4045 *
4046 * Destroys all resources associated with the IPA resource manager
4047 *
4048 * Return: None
4049 */
4050static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
4051{
4052 int ret;
4053
4054 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4055 return;
4056
4057 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304058 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004059
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004060 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304061 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004062
4063 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4064
4065 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4066 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304067 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004068 "RM PROD resource delete failed %d", ret);
4069
4070 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4071 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304072 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004073 "RM CONS resource delete failed %d", ret);
4074}
4075
4076/**
4077 * hdd_ipa_send_skb_to_network() - Send skb to kernel
4078 * @skb: network buffer
4079 * @adapter: network adapter
4080 *
4081 * Called when a network buffer is received which should not be routed
4082 * to the IPA module.
4083 *
4084 * Return: None
4085 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304086static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004087 hdd_adapter_t *adapter)
4088{
4089 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4090 unsigned int cpu_index;
4091
4092 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004093 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004094 adapter);
4095 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004096 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004097 return;
4098 }
4099
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004100 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004101 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004102 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004103 return;
4104 }
4105
4106 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
4107 skb->dev = adapter->dev;
4108 skb->protocol = eth_type_trans(skb, skb->dev);
4109 skb->ip_summed = CHECKSUM_NONE;
4110
4111 cpu_index = wlan_hdd_get_cpu();
4112
4113 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
4114 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
4115 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
4116 else
4117 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
4118
4119 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
4120 adapter->dev->last_rx = jiffies;
4121}
4122
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004123/**
Leo Chang69c39692016-10-12 20:11:12 -07004124 * hdd_ipa_forward() - handle packet forwarding to wlan tx
4125 * @hdd_ipa: pointer to hdd ipa context
4126 * @adapter: network adapter
4127 * @skb: data pointer
4128 *
4129 * if exception packet has set forward bit, copied new packet should be
4130 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
4131 * put into pm queue and tx procedure will be differed
4132 *
4133 * Return: None
4134 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07004135static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
4136 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07004137{
Leo Chang69c39692016-10-12 20:11:12 -07004138 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
4139
Leo Chang69c39692016-10-12 20:11:12 -07004140 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
4141 /* WLAN subsystem is in suspend, put int queue */
4142 if (hdd_ipa->suspended) {
4143 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4144 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4145 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004146 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
4147 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07004148 pm_tx_cb->exception = true;
4149 pm_tx_cb->adapter = adapter;
4150 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004151 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07004152 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4153 hdd_ipa->stats.num_tx_queued++;
4154 } else {
4155 /* Resume, put packet into WLAN TX */
4156 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004157 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07004158 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4159 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08004160 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07004161 } else {
Yun Parkb187d542016-11-14 18:10:04 -08004162 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07004163 hdd_ipa->ipa_tx_forward++;
4164 }
4165 }
4166}
4167
4168/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004169 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
4170 * @hdd_ipa: pointer to HDD IPA struct
4171 * @adapter: hdd adapter pointer
4172 * @desc: Firmware descriptor
4173 * @skb: Data buffer
4174 *
4175 * Return:
4176 * HDD_IPA_FORWARD_PKT_NONE
4177 * HDD_IPA_FORWARD_PKT_DISCARD
4178 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
4179 *
4180 */
4181
4182static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
4183 struct hdd_ipa_priv *hdd_ipa,
4184 hdd_adapter_t *adapter,
4185 uint8_t desc,
4186 qdf_nbuf_t skb)
4187{
4188 int ret = HDD_IPA_FORWARD_PKT_NONE;
4189
4190 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304191 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004192 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
4193 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304194 /* Drop the packet*/
4195 hdd_ipa->stats.num_tx_fwd_err++;
4196 kfree_skb(skb);
4197 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4198 return ret;
4199 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004200 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
4201 "Forward packet to Tx (fw_desc=%d)", desc);
4202 hdd_ipa->ipa_tx_forward++;
4203
4204 if ((desc & FW_RX_DESC_DISCARD_M)) {
4205 hdd_ipa_forward(hdd_ipa, adapter, skb);
4206 hdd_ipa->ipa_rx_internel_drop_count++;
4207 hdd_ipa->ipa_rx_discard++;
4208 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4209 } else {
4210 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004211
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004212 if (cloned_skb)
4213 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
4214 else
4215 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4216 "%s: tx skb alloc failed",
4217 __func__);
4218 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
4219 }
4220 }
4221
4222 return ret;
4223}
4224
4225/**
Yun Park637d6482016-10-05 10:51:33 -07004226 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004227 * @priv: pointer to private data registered with IPA (we register a
4228 * pointer to the global IPA context)
4229 * @evt: the IPA event which triggered the callback
4230 * @data: data associated with the event
4231 *
4232 * Return: None
4233 */
Yun Parkf8d6a122016-10-11 15:49:43 -07004234static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004235 unsigned long data)
4236{
4237 struct hdd_ipa_priv *hdd_ipa = NULL;
4238 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304239 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004240 uint8_t iface_id;
4241 uint8_t session_id;
4242 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004243 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07004244 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004245
4246 hdd_ipa = (struct hdd_ipa_priv *)priv;
4247
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08004248 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
4249 return;
4250
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251 switch (evt) {
4252 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05304253 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07004254
4255 /*
4256 * When SSR is going on or driver is unloading,
4257 * just drop the packets.
4258 */
4259 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4260 if (0 != status) {
4261 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4262 "Invalid context: drop packet");
4263 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4264 kfree_skb(skb);
4265 return;
4266 }
4267
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004268 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4269 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004270 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004271 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004272 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4273 session_id, iface_id);
4274 } else {
4275 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4276 }
4277
4278 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304279 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 "IPA_RECEIVE: Invalid iface_id: %u",
4281 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004282 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004283 "w2i -- skb",
4284 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004285 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004286 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004287 return;
4288 }
4289
4290 iface_context = &hdd_ipa->iface_context[iface_id];
4291 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08004292 if (!adapter) {
4293 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4294 "IPA_RECEIVE: Adapter is NULL");
4295 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4296 kfree_skb(skb);
4297 return;
4298 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004299
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304300 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004301 "w2i -- skb",
4302 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004303 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4304 hdd_ipa->stats.num_rx_excep++;
4305 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4306 } else {
4307 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4308 }
4309
4310 iface_context->stats.num_rx_ipa_excep++;
4311
4312 /* Disable to forward Intra-BSS Rx packets when
4313 * ap_isolate=1 in hostapd.conf
4314 */
Yun Park046101c2016-09-02 15:32:14 -07004315 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004316 /*
4317 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4318 * all Rx packets to IPA uC, which need to be forwarded
4319 * to other interface.
4320 * And, IPA driver will send back to WLAN host driver
4321 * through exception pipe with fw_desc field set by FW.
4322 * Here we are checking fw_desc field for FORWARD bit
4323 * set, and forward to Tx. Then copy to kernel stack
4324 * only when DISCARD bit is not set.
4325 */
4326 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004327 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4328 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4329 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004330 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004331 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004332 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004333 "Intra-BSS FWD is disabled-skip forward to Tx");
4334 }
4335
4336 hdd_ipa_send_skb_to_network(skb, adapter);
4337 break;
4338
4339 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304340 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004341 "w2i cb wrong event: 0x%x", evt);
4342 return;
4343 }
4344}
4345
4346/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004347 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4348 * @priv: pointer to private data registered with IPA (we register a
4349 * pointer to the global IPA context)
4350 * @evt: the IPA event which triggered the callback
4351 * @data: data associated with the event
4352 *
4353 * Return: None
4354 */
4355static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
4356 unsigned long data)
4357{
4358 cds_ssr_protect(__func__);
4359 __hdd_ipa_w2i_cb(priv, evt, data);
4360 cds_ssr_unprotect(__func__);
4361}
4362
4363/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004364 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4365 * @skb: packet buffer which was transmitted
4366 *
4367 * Return: None
4368 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304369void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370{
4371 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park52b2b992016-09-22 15:49:51 -07004372 struct ipa_rx_data *ipa_tx_desc;
4373 struct hdd_ipa_tx_desc *tx_desc;
4374 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004375
Yun Park52b2b992016-09-22 15:49:51 -07004376 if (!qdf_nbuf_ipa_owned_get(skb)) {
4377 dev_kfree_skb_any(skb);
4378 return;
4379 }
4380
4381 /* Get Tx desc pointer from SKB CB */
4382 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4383 tx_desc = hdd_ipa->tx_desc_list + id;
4384 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4385
4386 /* Return Tx Desc to IPA */
4387 ipa_free_skb(ipa_tx_desc);
4388
4389 /* Return to free tx desc list */
4390 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4391 tx_desc->ipa_tx_desc_ptr = NULL;
4392 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4393 hdd_ipa->stats.num_tx_desc_q_cnt--;
4394 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004395
4396 hdd_ipa->stats.num_tx_comp_cnt++;
4397
4398 atomic_dec(&hdd_ipa->tx_ref_cnt);
4399
4400 hdd_ipa_rm_try_release(hdd_ipa);
4401}
4402
4403/**
4404 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4405 * @iface_context: interface-specific IPA context
4406 * @ipa_tx_desc: packet data descriptor
4407 *
4408 * Return: None
4409 */
4410static void hdd_ipa_send_pkt_to_tl(
4411 struct hdd_ipa_iface_context *iface_context,
4412 struct ipa_rx_data *ipa_tx_desc)
4413{
4414 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004415 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304416 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004417 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004418
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304419 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004420 adapter = iface_context->adapter;
4421 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304422 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423 ipa_free_skb(ipa_tx_desc);
4424 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304425 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004426 hdd_ipa_rm_try_release(hdd_ipa);
4427 return;
4428 }
4429
4430 /*
4431 * During CAC period, data packets shouldn't be sent over the air so
4432 * drop all the packets here
4433 */
4434 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4435 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304436 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004437 iface_context->stats.num_tx_cac_drop++;
4438 hdd_ipa_rm_try_release(hdd_ipa);
4439 return;
4440 }
4441
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004442 ++adapter->stats.tx_packets;
4443
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304444 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004445
4446 skb = ipa_tx_desc->skb;
4447
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304448 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004449
4450 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304451 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004452 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304453 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004454 ipa_tx_desc->dma_addr
4455 + HDD_IPA_WLAN_FRAG_HEADER
4456 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004457 ipa_tx_desc->skb->len -=
4458 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4459 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304460 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004461
Yun Park52b2b992016-09-22 15:49:51 -07004462 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4463 /* get free Tx desc and assign ipa_tx_desc pointer */
4464 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4465 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4466 struct hdd_ipa_tx_desc, link);
4467 list_del(&tx_desc->link);
4468 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4469 hdd_ipa->stats.num_tx_desc_q_cnt++;
4470 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4471 /* Store Tx Desc index into SKB CB */
4472 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4473 } else {
4474 hdd_ipa->stats.num_tx_desc_error++;
4475 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4476 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "No free Tx desc!");
4477 ipa_free_skb(ipa_tx_desc);
4478 hdd_ipa_rm_try_release(hdd_ipa);
4479 return;
4480 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004481
4482 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
4483
Leo Changfdb45c32016-10-28 11:09:23 -07004484 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004485 (struct cdp_vdev *)iface_context->tl_context,
4486 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004487 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304488 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004489 ipa_free_skb(ipa_tx_desc);
4490 iface_context->stats.num_tx_err++;
4491 hdd_ipa_rm_try_release(hdd_ipa);
4492 return;
4493 }
4494
4495 atomic_inc(&hdd_ipa->tx_ref_cnt);
4496
4497 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498}
4499
4500/**
Leo Chang11545d62016-10-17 14:53:50 -07004501 * hdd_ipa_is_present() - get IPA hw status
4502 * @hdd_ctx: pointer to hdd context
4503 *
4504 * ipa_uc_reg_rdyCB is not directly designed to check
4505 * ipa hw status. This is an undocumented function which
4506 * has confirmed with IPA team.
4507 *
4508 * Return: true - ipa hw present
4509 * false - ipa hw not present
4510 */
4511bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
4512{
4513 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004514 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004515 return true;
4516 else
4517 return false;
4518}
4519
4520/**
Leo Chang69c39692016-10-12 20:11:12 -07004521 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004522 * @work: pointer to the scheduled work
4523 *
4524 * Called during PM resume to send packets to TL which were queued
4525 * while host was in the process of suspending.
4526 *
4527 * Return: None
4528 */
Leo Chang69c39692016-10-12 20:11:12 -07004529static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004530{
4531 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4532 struct hdd_ipa_priv,
4533 pm_work);
4534 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304535 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004536 uint32_t dequeued = 0;
4537
Leo Chang69c39692016-10-12 20:11:12 -07004538 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4539 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304540 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304541 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4542 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304543 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004544
4545 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004546 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004547 if (pm_tx_cb->exception) {
4548 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4549 "FLUSH EXCEPTION");
4550 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
4551 } else {
4552 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004553 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004554 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304555 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004556 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304557 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004558 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4559 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004560
4561 hdd_ipa->stats.num_tx_dequeued += dequeued;
4562 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4563 hdd_ipa->stats.num_max_pm_queue = dequeued;
4564}
4565
4566/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004567 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004568 * @priv: pointer to private data registered with IPA (we register a
4569 * pointer to the interface-specific IPA context)
4570 * @evt: the IPA event which triggered the callback
4571 * @data: data associated with the event
4572 *
4573 * Return: None
4574 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004575static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004576 unsigned long data)
4577{
4578 struct hdd_ipa_priv *hdd_ipa = NULL;
4579 struct ipa_rx_data *ipa_tx_desc;
4580 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304581 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004582 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304583 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004584
Mukul Sharma81661ae2015-10-30 20:26:02 +05304585 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004586 ipa_tx_desc = (struct ipa_rx_data *)data;
4587 hdd_ipa = iface_context->hdd_ipa;
4588
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004589 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004590 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4591 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004592 iface_context->stats.num_tx_drop++;
4593 return;
4594 }
4595
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004596 /*
4597 * When SSR is going on or driver is unloading, just drop the packets.
4598 * During SSR, there is no use in queueing the packets as STA has to
4599 * connect back any way
4600 */
4601 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304602 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004603 ipa_free_skb(ipa_tx_desc);
4604 iface_context->stats.num_tx_drop++;
4605 return;
4606 }
4607
4608 skb = ipa_tx_desc->skb;
4609
Yun Parkb187d542016-11-14 18:10:04 -08004610 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4611 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004612
4613 /*
4614 * If PROD resource is not requested here then there may be cases where
4615 * IPA hardware may be clocked down because of not having proper
4616 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4617 * workaround to request PROD resource while data is going over CONS
4618 * pipe to prevent the IPA hardware clockdown.
4619 */
4620 hdd_ipa_rm_request(hdd_ipa);
4621
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304622 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623 /*
4624 * If host is still suspended then queue the packets and these will be
4625 * drained later when resume completes. When packet is arrived here and
4626 * host is suspended, this means that there is already resume is in
4627 * progress.
4628 */
4629 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304630 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004631 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4632 pm_tx_cb->iface_context = iface_context;
4633 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304634 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004635 hdd_ipa->stats.num_tx_queued++;
4636
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304637 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 return;
4639 }
4640
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304641 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004642
4643 /*
4644 * If we are here means, host is not suspended, wait for the work queue
4645 * to finish.
4646 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004647 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004648
4649 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4650}
4651
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004652/*
4653 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4654 * @priv: pointer to private data registered with IPA (we register a
4655 * pointer to the interface-specific IPA context)
4656 * @evt: the IPA event which triggered the callback
4657 * @data: data associated with the event
4658 *
4659 * Return: None
4660 */
4661static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
4662 unsigned long data)
4663{
4664 cds_ssr_protect(__func__);
4665 __hdd_ipa_i2w_cb(priv, evt, data);
4666 cds_ssr_unprotect(__func__);
4667}
4668
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004670 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004671 * @hdd_ctx: Global HDD context
4672 *
4673 * Return: 0 on success, negativer errno on error
4674 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004675static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004676{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004677 struct hdd_ipa_priv *hdd_ipa;
4678
4679 if (wlan_hdd_validate_context(hdd_ctx))
4680 return 0;
4681
4682 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004683
4684 if (!hdd_ipa_is_enabled(hdd_ctx))
4685 return 0;
4686
4687 /*
4688 * Check if IPA is ready for suspend, If we are here means, there is
4689 * high chance that suspend would go through but just to avoid any race
4690 * condition after suspend started, these checks are conducted before
4691 * allowing to suspend.
4692 */
4693 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4694 return -EAGAIN;
4695
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304696 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004697
4698 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304699 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004700 return -EAGAIN;
4701 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304702 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004703
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304704 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004705 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304706 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707
4708 return 0;
4709}
4710
4711/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004712 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4713 * @hdd_ctx: Global HDD context
4714 *
4715 * Return: 0 on success, negativer errno on error
4716 */
4717int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4718{
4719 int ret;
4720
4721 cds_ssr_protect(__func__);
4722 ret = __hdd_ipa_suspend(hdd_ctx);
4723 cds_ssr_unprotect(__func__);
4724
4725 return ret;
4726}
4727
4728/**
4729 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004730 * hdd_ctx: Global HDD context
4731 *
4732 * Return: 0 on success, negative errno on error
4733 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004734static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004735{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004736 struct hdd_ipa_priv *hdd_ipa;
4737
4738 if (wlan_hdd_validate_context(hdd_ctx))
4739 return 0;
4740
4741 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004742
4743 if (!hdd_ipa_is_enabled(hdd_ctx))
4744 return 0;
4745
4746 schedule_work(&hdd_ipa->pm_work);
4747
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304748 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004749 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304750 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004751
4752 return 0;
4753}
4754
4755/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004756 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4757 * hdd_ctx: Global HDD context
4758 *
4759 * Return: 0 on success, negative errno on error
4760 */
4761int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4762{
4763 int ret;
4764
4765 cds_ssr_protect(__func__);
4766 ret = __hdd_ipa_resume(hdd_ctx);
4767 cds_ssr_unprotect(__func__);
4768
4769 return ret;
4770}
4771
4772/**
Yun Park52b2b992016-09-22 15:49:51 -07004773 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
4774 * @hdd_ipa: Global HDD IPA context
4775 *
4776 * Return: 0 on success, negative errno on error
4777 */
4778static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
4779{
4780 int i;
4781 uint32_t max_desc_cnt;
4782 struct hdd_ipa_tx_desc *tmp_desc;
4783
4784 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
4785
4786 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
4787
4788 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc)*max_desc_cnt);
4789
4790 if (!tmp_desc) {
4791 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4792 "Free Tx descriptor allocation failed");
4793 return -ENOMEM;
4794 }
4795
4796 hdd_ipa->tx_desc_list = tmp_desc;
4797
4798 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4799 for (i = 0; i < max_desc_cnt; i++) {
4800 tmp_desc->id = i;
4801 tmp_desc->ipa_tx_desc_ptr = NULL;
4802 list_add_tail(&tmp_desc->link,
4803 &hdd_ipa->free_tx_desc_head);
4804 tmp_desc++;
4805 }
4806
4807 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4808 hdd_ipa->stats.num_tx_desc_error = 0;
4809
4810 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4811
4812 return 0;
4813}
4814
4815/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004816 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4817 * @hdd_ipa: Global HDD IPA context
4818 *
4819 * Return: 0 on success, negative errno on error
4820 */
4821static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4822{
4823 int i, ret = 0;
4824 struct ipa_sys_connect_params *ipa;
4825 uint32_t desc_fifo_sz;
4826
4827 /* The maximum number of descriptors that can be provided to a BAM at
4828 * once is one less than the total number of descriptors that the buffer
4829 * can contain.
4830 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4831 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4832 * be provided at once.
4833 * Because of above requirement, one extra descriptor will be added to
4834 * make sure hardware always has one descriptor.
4835 */
4836 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4837 + sizeof(struct sps_iovec);
4838
4839 /*setup TX pipes */
4840 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4841 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4842
4843 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4844 ipa->desc_fifo_sz = desc_fifo_sz;
4845 ipa->priv = &hdd_ipa->iface_context[i];
4846 ipa->notify = hdd_ipa_i2w_cb;
4847
4848 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4849 ipa->ipa_ep_cfg.hdr.hdr_len =
4850 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4851 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4852 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4853 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4854 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4855 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4856 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4857 } else {
4858 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4859 }
4860 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4861
4862 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4863 ipa->keep_ipa_awake = 1;
4864
4865 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4866 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004867 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4868 "Failed for pipe %d ret: %d", i, ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004869 goto setup_sys_pipe_fail;
4870 }
4871 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4872 }
4873
4874 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4875 /*
4876 * Hard code it here, this can be extended if in case
4877 * PROD pipe is also per interface.
4878 * Right now there is no advantage of doing this.
4879 */
4880 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4881
4882 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4883
4884 ipa->client = hdd_ipa->prod_client;
4885
4886 ipa->desc_fifo_sz = desc_fifo_sz;
4887 ipa->priv = hdd_ipa;
4888 ipa->notify = hdd_ipa_w2i_cb;
4889
4890 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4891 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4892 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4893 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4894
4895 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4896 ipa->keep_ipa_awake = 1;
4897
4898 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4899 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304900 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004901 "Failed for RX pipe: %d", ret);
4902 goto setup_sys_pipe_fail;
4903 }
4904 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4905 }
4906
Yun Park52b2b992016-09-22 15:49:51 -07004907 /* Allocate free Tx desc list */
4908 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
4909 if (ret)
4910 goto setup_sys_pipe_fail;
4911
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004912 return ret;
4913
4914setup_sys_pipe_fail:
4915
4916 while (--i >= 0) {
4917 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304918 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004919 sizeof(struct hdd_ipa_sys_pipe));
4920 }
4921
4922 return ret;
4923}
4924
4925/**
4926 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4927 * @hdd_ipa: Global HDD IPA context
4928 *
4929 * Return: None
4930 */
4931static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4932{
4933 int ret = 0, i;
Yun Park52b2b992016-09-22 15:49:51 -07004934 uint32_t max_desc_cnt;
4935 struct hdd_ipa_tx_desc *tmp_desc;
4936 struct ipa_rx_data *ipa_tx_desc;
4937
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004938 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4939 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4940 ret =
4941 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4942 conn_hdl);
4943 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304944 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004945 ret);
4946
4947 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4948 }
4949 }
Yun Park52b2b992016-09-22 15:49:51 -07004950
4951 if (hdd_ipa->tx_desc_list) {
4952 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
4953
4954 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4955 for (i = 0; i < max_desc_cnt; i++) {
4956 tmp_desc = hdd_ipa->tx_desc_list + i;
4957 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
4958 if (ipa_tx_desc)
4959 ipa_free_skb(ipa_tx_desc);
4960 }
4961 tmp_desc = hdd_ipa->tx_desc_list;
4962 hdd_ipa->tx_desc_list = NULL;
4963 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4964 hdd_ipa->stats.num_tx_desc_error = 0;
4965 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4966 qdf_mem_free(tmp_desc);
4967 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004968}
4969
4970/**
4971 * hdd_ipa_register_interface() - register IPA interface
4972 * @hdd_ipa: Global IPA context
4973 * @iface_context: Per-interface IPA context
4974 *
4975 * Return: 0 on success, negative errno on error
4976 */
4977static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
4978 struct hdd_ipa_iface_context
4979 *iface_context)
4980{
4981 struct ipa_tx_intf tx_intf;
4982 struct ipa_rx_intf rx_intf;
4983 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
4984 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
4985 char *ifname = iface_context->adapter->dev->name;
4986
4987 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
4988 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
4989
4990 int num_prop = 1;
4991 int ret = 0;
4992
4993 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
4994 num_prop++;
4995
4996 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
4997 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304998 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305000 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005001 goto register_interface_fail;
5002 }
5003
5004 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
5005 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305006 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005007 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305008 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005009 goto register_interface_fail;
5010 }
5011
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305012 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
5013 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005014
5015 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
5016 ifname, HDD_IPA_IPV4_NAME_EXT);
5017 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
5018 ifname, HDD_IPA_IPV6_NAME_EXT);
5019
5020 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
5021 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
5022 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5023 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
5024
5025 /*
5026 * Interface ID is 3rd byte in the CLD header. Add the meta data and
5027 * mask to identify the interface in IPA hardware
5028 */
5029 rx_prop[IPA_IP_v4].attrib.meta_data =
5030 htonl(iface_context->adapter->sessionId << 16);
5031 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
5032
5033 rx_intf.num_props++;
5034 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5035 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
5036 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
5037 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5038 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
5039 rx_prop[IPA_IP_v4].attrib.meta_data =
5040 htonl(iface_context->adapter->sessionId << 16);
5041 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
5042
5043 rx_intf.num_props++;
5044 }
5045
5046 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
5047 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5048 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
5049 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
5050 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
5051 IPA_RESOURCE_NAME_MAX);
5052 tx_intf.num_props++;
5053
5054 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5055 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
5056 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5057 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
5058 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
5059 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
5060 IPA_RESOURCE_NAME_MAX);
5061 tx_intf.num_props++;
5062 }
5063
5064 tx_intf.prop = tx_prop;
5065 rx_intf.prop = rx_prop;
5066
5067 /* Call the ipa api to register interface */
5068 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
5069
Yun Park52b2b992016-09-22 15:49:51 -07005070 /* Register IPA Tx desc free callback */
5071 qdf_nbuf_reg_free_cb(hdd_ipa_nbuf_cb);
5072
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005073register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305074 qdf_mem_free(tx_prop);
5075 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005076 return ret;
5077}
5078
5079/**
5080 * hdd_remove_ipa_header() - Remove a specific header from IPA
5081 * @name: Name of the header to be removed
5082 *
5083 * Return: None
5084 */
5085static void hdd_ipa_remove_header(char *name)
5086{
5087 struct ipa_ioc_get_hdr hdrlookup;
5088 int ret = 0, len;
5089 struct ipa_ioc_del_hdr *ipa_hdr;
5090
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305091 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005092 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
5093 ret = ipa_get_hdr(&hdrlookup);
5094 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005095 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005096 name, ret);
5097 return;
5098 }
5099
Srinivas Girigowda97852372017-03-06 16:52:59 -08005100 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005101 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305102 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005103 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305104 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005105 return;
5106 }
5107 ipa_hdr->num_hdls = 1;
5108 ipa_hdr->commit = 0;
5109 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
5110 ipa_hdr->hdl[0].status = -1;
5111 ret = ipa_del_hdr(ipa_hdr);
5112 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305113 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005114 ret);
5115
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305116 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005117}
5118
5119/**
Yun Parkb187d542016-11-14 18:10:04 -08005120 * wlan_ipa_add_hdr() - Add IPA Tx header
5121 * @ipa_hdr: pointer to IPA header addition parameters
5122 *
5123 * Call IPA API to add IPA Tx header descriptor
5124 * and dump Tx header struct
5125 *
5126 * Return: 0 for success, non-zero for failure
5127 */
5128static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
5129{
5130 int ret;
5131
Srinivas Girigowda97852372017-03-06 16:52:59 -08005132 hdd_debug("==== IPA Tx Header ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08005133 "name: %s\n"
5134 "hdr_len: %d\n"
5135 "type: %d\n"
5136 "is_partial: %d\n"
5137 "hdr_hdl: 0x%x\n"
5138 "status: %d\n"
5139 "is_eth2_ofst_valid: %d\n"
5140 "eth2_ofst: %d\n",
5141 ipa_hdr->hdr[0].name,
5142 ipa_hdr->hdr[0].hdr_len,
5143 ipa_hdr->hdr[0].type,
5144 ipa_hdr->hdr[0].is_partial,
5145 ipa_hdr->hdr[0].hdr_hdl,
5146 ipa_hdr->hdr[0].status,
5147 ipa_hdr->hdr[0].is_eth2_ofst_valid,
5148 ipa_hdr->hdr[0].eth2_ofst);
5149
Srinivas Girigowdac06543c2017-03-09 15:10:03 -08005150 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, "hdr:",
Yun Parkb187d542016-11-14 18:10:04 -08005151 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
5152
5153 ret = ipa_add_hdr(ipa_hdr);
5154 return ret;
5155}
5156
5157/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005158 * hdd_ipa_add_header_info() - Add IPA header for a given interface
5159 * @hdd_ipa: Global HDD IPA context
5160 * @iface_context: Interface-specific HDD IPA context
5161 * @mac_addr: Interface MAC address
5162 *
5163 * Return: 0 on success, negativer errno value on error
5164 */
5165static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
5166 struct hdd_ipa_iface_context *iface_context,
5167 uint8_t *mac_addr)
5168{
5169 hdd_adapter_t *adapter = iface_context->adapter;
5170 char *ifname;
5171 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
5172 int ret = -EINVAL;
5173 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
5174 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
5175
5176 ifname = adapter->dev->name;
5177
Srinivas Girigowda97852372017-03-06 16:52:59 -08005178 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005179 ifname, mac_addr);
5180
5181 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305182 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005183 + sizeof(struct ipa_hdr_add));
5184 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305185 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005186 "%s: ipa_hdr allocation failed", ifname);
5187 ret = -ENOMEM;
5188 goto end;
5189 }
5190
5191 ipa_hdr->commit = 0;
5192 ipa_hdr->num_hdrs = 1;
5193
5194 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5195 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
5196 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
5197 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
5198 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305199 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005200 "ifname=%s, vdev_id=%d",
5201 ifname, uc_tx_hdr->ipa_hd.vdev_id);
5202 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5203 ifname, HDD_IPA_IPV4_NAME_EXT);
5204 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
5205 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
5206 ipa_hdr->hdr[0].is_partial = 1;
5207 ipa_hdr->hdr[0].hdr_hdl = 0;
5208 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
5209 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5210
Yun Parkb187d542016-11-14 18:10:04 -08005211 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005212 } else {
5213 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
5214
5215 /* Set the Source MAC */
5216 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
5217 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
5218
5219 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5220 ifname, HDD_IPA_IPV4_NAME_EXT);
5221 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
5222 ipa_hdr->hdr[0].is_partial = 1;
5223 ipa_hdr->hdr[0].hdr_hdl = 0;
5224 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
5225 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5226
5227 /* Set the type to IPV4 in the header */
5228 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
5229
5230 ret = ipa_add_hdr(ipa_hdr);
5231 }
5232 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305233 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005234 ifname, ret);
5235 goto end;
5236 }
5237
Srinivas Girigowda97852372017-03-06 16:52:59 -08005238 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005239 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
5240
5241 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5242 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5243 ifname, HDD_IPA_IPV6_NAME_EXT);
5244
5245 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5246 uc_tx_hdr =
5247 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
5248 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08005249 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005250 } else {
5251 /* Set the type to IPV6 in the header */
5252 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
5253 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08005254 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005255 }
5256
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005257 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305258 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005259 "%s: IPv6 add hdr failed: %d", ifname, ret);
5260 goto clean_ipv4_hdr;
5261 }
5262
Srinivas Girigowda97852372017-03-06 16:52:59 -08005263 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005264 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
5265 }
5266
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305267 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005268
5269 return ret;
5270
5271clean_ipv4_hdr:
5272 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5273 ifname, HDD_IPA_IPV4_NAME_EXT);
5274 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
5275end:
5276 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305277 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005278
5279 return ret;
5280}
5281
5282/**
5283 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
5284 * @adapter: Adapter upon which IPA was previously configured
5285 *
5286 * Return: None
5287 */
5288static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
5289{
5290 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5291 int ret;
5292 char name_ipa[IPA_RESOURCE_NAME_MAX];
5293
5294 /* Remove the headers */
5295 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
5296 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
5297 hdd_ipa_remove_header(name_ipa);
5298
5299 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5300 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
5301 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
5302 hdd_ipa_remove_header(name_ipa);
5303 }
5304 /* unregister the interface with IPA */
5305 ret = ipa_deregister_intf(adapter->dev->name);
5306 if (ret)
Srinivas Girigowda97852372017-03-06 16:52:59 -08005307 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005308 "%s: ipa_deregister_intf fail: %d",
5309 adapter->dev->name, ret);
5310}
5311
5312/**
5313 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
5314 * @iface_context: interface-specific IPA context
5315 *
5316 * Return: None
5317 */
5318static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
5319{
5320 if (iface_context == NULL)
5321 return;
5322
5323 hdd_ipa_clean_hdr(iface_context->adapter);
5324
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305325 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005326 iface_context->adapter->ipa_context = NULL;
5327 iface_context->adapter = NULL;
5328 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305329 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005330 iface_context->ifa_address = 0;
5331 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305332 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005333 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05305334 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005335 }
5336 iface_context->hdd_ipa->num_iface--;
5337}
5338
5339/**
5340 * hdd_ipa_setup_iface() - Setup IPA on a given interface
5341 * @hdd_ipa: HDD IPA global context
5342 * @adapter: Interface upon which IPA is being setup
5343 * @sta_id: Station ID of the API instance
5344 *
5345 * Return: 0 on success, negative errno value on error
5346 */
5347static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
5348 hdd_adapter_t *adapter, uint8_t sta_id)
5349{
5350 struct hdd_ipa_iface_context *iface_context = NULL;
5351 void *tl_context = NULL;
5352 int i, ret = 0;
5353
5354 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
5355 * channel change indication. Since these indications are sent by lower
5356 * layer as SAP updates and IPA doesn't have to do anything for these
5357 * updates so ignoring!
5358 */
Krunal Sonibe766b02016-03-10 13:00:44 -08005359 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005360 return 0;
5361
5362 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5363 if (hdd_ipa->iface_context[i].adapter == NULL) {
5364 iface_context = &(hdd_ipa->iface_context[i]);
5365 break;
5366 }
5367 }
5368
5369 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305370 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005371 "All the IPA interfaces are in use");
5372 ret = -ENOMEM;
5373 goto end;
5374 }
5375
5376 adapter->ipa_context = iface_context;
5377 iface_context->adapter = adapter;
5378 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08005379 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07005380 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005381 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305382 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005383 "Not able to get TL context sta_id: %d", sta_id);
5384 ret = -EINVAL;
5385 goto end;
5386 }
5387
5388 iface_context->tl_context = tl_context;
5389
5390 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
5391 adapter->dev->dev_addr);
5392
5393 if (ret)
5394 goto end;
5395
5396 /* Configure the TX and RX pipes filter rules */
5397 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
5398 if (ret)
5399 goto cleanup_header;
5400
5401 hdd_ipa->num_iface++;
5402 return ret;
5403
5404cleanup_header:
5405
5406 hdd_ipa_clean_hdr(adapter);
5407end:
5408 if (iface_context)
5409 hdd_ipa_cleanup_iface(iface_context);
5410 return ret;
5411}
5412
Yun Parka27049a2016-10-11 12:30:49 -07005413#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005414/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005415 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005416 * @mcc_mode: 0=MCC/1=SCC
5417 *
5418 * Return: 0 on success, negative errno value on error
5419 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005420static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005421{
5422 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305423 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005424 hdd_adapter_t *pAdapter;
5425 struct ipa_msg_meta meta;
5426 struct ipa_wlan_msg *msg;
5427 int ret;
5428
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005429 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005430 return -EINVAL;
5431
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005432 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
5433 return -EINVAL;
5434
5435 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005436 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005437 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305438 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005439 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08005440 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005441 pAdapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005442 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005443 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005444 hdd_deinit_tx_rx(pAdapter);
5445 }
5446 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005447 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005448 adapter_node = next;
5449 }
5450 }
5451
5452 /* Send SCC/MCC Switching event to IPA */
5453 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305454 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005455 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005456 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005457 return -ENOMEM;
5458 }
5459
5460 meta.msg_type = mcc_mode ?
5461 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Srinivas Girigowda97852372017-03-06 16:52:59 -08005462 hdd_debug("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005463
5464 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5465
5466 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005467 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005468 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305469 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005470 }
5471
5472 return ret;
5473}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005474
5475/**
5476 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5477 * @mcc_mode: 0=MCC/1=SCC
5478 *
5479 * Return: 0 on success, negative errno value on error
5480 */
5481int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
5482{
5483 int ret;
5484
5485 cds_ssr_protect(__func__);
5486 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5487 cds_ssr_unprotect(__func__);
5488
5489 return ret;
5490}
Yun Parka27049a2016-10-11 12:30:49 -07005491#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005492
5493/**
5494 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
5495 * @event: IPA WLAN event to be converted to a string
5496 *
5497 * Return: ASCII string representing the IPA WLAN event
5498 */
5499static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
5500{
5501 switch (event) {
5502 case WLAN_CLIENT_CONNECT:
5503 return "WLAN_CLIENT_CONNECT";
5504 case WLAN_CLIENT_DISCONNECT:
5505 return "WLAN_CLIENT_DISCONNECT";
5506 case WLAN_CLIENT_POWER_SAVE_MODE:
5507 return "WLAN_CLIENT_POWER_SAVE_MODE";
5508 case WLAN_CLIENT_NORMAL_MODE:
5509 return "WLAN_CLIENT_NORMAL_MODE";
5510 case SW_ROUTING_ENABLE:
5511 return "SW_ROUTING_ENABLE";
5512 case SW_ROUTING_DISABLE:
5513 return "SW_ROUTING_DISABLE";
5514 case WLAN_AP_CONNECT:
5515 return "WLAN_AP_CONNECT";
5516 case WLAN_AP_DISCONNECT:
5517 return "WLAN_AP_DISCONNECT";
5518 case WLAN_STA_CONNECT:
5519 return "WLAN_STA_CONNECT";
5520 case WLAN_STA_DISCONNECT:
5521 return "WLAN_STA_DISCONNECT";
5522 case WLAN_CLIENT_CONNECT_EX:
5523 return "WLAN_CLIENT_CONNECT_EX";
5524
5525 case IPA_WLAN_EVENT_MAX:
5526 default:
5527 return "UNKNOWN";
5528 }
5529}
5530
5531/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005532 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5533 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5534 *
5535 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
5536 */
5537static enum ipa_wlan_event
5538hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5539{
5540 enum ipa_wlan_event ipa_event;
5541
5542 switch (hdd_ipa_event_type) {
5543 case HDD_IPA_CLIENT_CONNECT:
5544 ipa_event = WLAN_CLIENT_CONNECT;
5545 break;
5546 case HDD_IPA_CLIENT_DISCONNECT:
5547 ipa_event = WLAN_CLIENT_DISCONNECT;
5548 break;
5549 case HDD_IPA_AP_CONNECT:
5550 ipa_event = WLAN_AP_CONNECT;
5551 break;
5552 case HDD_IPA_AP_DISCONNECT:
5553 ipa_event = WLAN_AP_DISCONNECT;
5554 break;
5555 case HDD_IPA_STA_CONNECT:
5556 ipa_event = WLAN_STA_CONNECT;
5557 break;
5558 case HDD_IPA_STA_DISCONNECT:
5559 ipa_event = WLAN_STA_DISCONNECT;
5560 break;
5561 case HDD_IPA_CLIENT_CONNECT_EX:
5562 ipa_event = WLAN_CLIENT_CONNECT_EX;
5563 break;
5564 case HDD_IPA_WLAN_EVENT_MAX:
5565 default:
5566 ipa_event = IPA_WLAN_EVENT_MAX;
5567 break;
5568 }
5569 return ipa_event;
5570
5571}
5572
5573/**
5574 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005575 * @adapter: adapter upon which the event was received
5576 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005577 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005578 * @mac_address: MAC address associated with the event
5579 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005580 * This function is meant to be called from within wlan_hdd_ipa.c
5581 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005582 * Return: 0 on success, negative errno value on error
5583 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07005584static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005585 enum ipa_wlan_event type, uint8_t *mac_addr)
5586{
5587 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5588 struct ipa_msg_meta meta;
5589 struct ipa_wlan_msg *msg;
5590 struct ipa_wlan_msg_ex *msg_ex = NULL;
5591 int ret;
5592
Srinivas Girigowda97852372017-03-06 16:52:59 -08005593 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005594 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5595 mac_addr, sta_id);
5596
5597 if (type >= IPA_WLAN_EVENT_MAX)
5598 return -EINVAL;
5599
5600 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5601 return -EINVAL;
5602
5603 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305604 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005605 return -EINVAL;
5606 }
5607
5608 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5609 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005610 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005611 return 0;
5612 }
5613
5614 /*
5615 * During IPA UC resource loading/unloading new events can be issued.
5616 * Store the events separately and handle them later.
5617 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005618 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5619 if (hdd_ipa->resource_loading) {
5620 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005621 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005622
Yun Park64c405e2017-01-10 22:35:51 -08005623 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5624 "IPA resource load in progress");
Yun Park7c4f31b2016-11-30 10:09:21 -08005625
Yun Park64c405e2017-01-10 22:35:51 -08005626 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005627
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005628 pending_event_count =
5629 qdf_list_size(&hdd_ipa->pending_event);
5630 if (pending_event_count >=
5631 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005632 hdd_debug("Reached max pending event count");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005633 qdf_list_remove_front(&hdd_ipa->pending_event,
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005634 (qdf_list_node_t **)&pending_event);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005635 } else {
5636 pending_event =
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005637 qdf_mem_malloc(sizeof(*pending_event));
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005638 }
5639
5640 if (!pending_event) {
Yun Park64c405e2017-01-10 22:35:51 -08005641 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park7c4f31b2016-11-30 10:09:21 -08005642 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5643 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005644 return -ENOMEM;
5645 }
5646
5647 pending_event->adapter = adapter;
5648 pending_event->sta_id = sta_id;
5649 pending_event->type = type;
5650 qdf_mem_copy(pending_event->mac_addr,
5651 mac_addr,
5652 QDF_MAC_ADDR_SIZE);
5653 qdf_list_insert_back(&hdd_ipa->pending_event,
5654 &pending_event->node);
5655
Yun Park64c405e2017-01-10 22:35:51 -08005656 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005657 return 0;
5658 } else if (hdd_ipa->resource_unloading) {
Yun Park64c405e2017-01-10 22:35:51 -08005659 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5660 "IPA resource unload in progress");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005661 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005662 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005663 }
5664
5665 hdd_ipa->stats.event[type]++;
5666
Leo Chang3bc8fed2015-11-13 10:59:47 -08005667 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005668 switch (type) {
5669 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005670 qdf_mutex_acquire(&hdd_ipa->event_lock);
5671
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005672 /* STA already connected and without disconnect, connect again
5673 * This is Roaming scenario
5674 */
5675 if (hdd_ipa->sta_connected)
5676 hdd_ipa_cleanup_iface(adapter->ipa_context);
5677
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005678 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5679 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305680 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005681 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005682 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005683
Yun Park8f289c82016-10-18 16:38:21 -07005684 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5685 (hdd_ipa->sap_num_connected_sta > 0) &&
5686 !hdd_ipa->sta_connected) {
5687 qdf_mutex_release(&hdd_ipa->event_lock);
5688 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005689 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005690 qdf_mutex_acquire(&hdd_ipa->event_lock);
5691 }
5692
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005693 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005694 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005695 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005696
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005697 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005698
5699 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005700 break;
5701
5702 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005703 qdf_mutex_acquire(&hdd_ipa->event_lock);
5704
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005705 /* For DFS channel we get two start_bss event (before and after
5706 * CAC). Also when ACS range includes both DFS and non DFS
5707 * channels, we could possibly change channel many times due to
5708 * RADAR detection and chosen channel may not be a DFS channels.
5709 * So dont return error here. Just discard the event.
5710 */
Yun Park8f289c82016-10-18 16:38:21 -07005711 if (adapter->ipa_context) {
5712 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005713 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005714 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005715
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005716 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5717 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005718 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005719 hdd_err("%s: Evt: %d, Interface setup failed",
5720 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005721 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005722 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005723
Yun Park8f289c82016-10-18 16:38:21 -07005724 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5725 qdf_mutex_release(&hdd_ipa->event_lock);
5726 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005727 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005728 qdf_mutex_acquire(&hdd_ipa->event_lock);
5729 }
5730
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005731 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005732 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005733 (adapter->ipa_context))->iface_id;
5734
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305735 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005736 break;
5737
5738 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305739 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005740
5741 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005742 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005743 hdd_err("%s: Evt: %d, STA already disconnected",
5744 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005745 return -EINVAL;
5746 }
Yun Parka37592b2016-06-11 17:10:28 -07005747
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005748 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005749
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005750 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005751 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005752 msg_ex->name);
5753 } else {
5754 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005755 if (!hdd_ipa->num_iface &&
5756 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305757 hdd_ipa->activated_fw_pipe) &&
5758 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005759 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005760 }
5761
Yun Park74127cf2016-09-18 11:22:41 -07005762 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5763 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005764 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005765 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005766 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005767 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005768 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5769 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005770 }
5771
Yun Park8f289c82016-10-18 16:38:21 -07005772 hdd_ipa_cleanup_iface(adapter->ipa_context);
5773
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305774 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005775 break;
5776
5777 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005778 qdf_mutex_acquire(&hdd_ipa->event_lock);
5779
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005780 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005781 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005782 hdd_err("%s: Evt: %d, SAP already disconnected",
5783 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005784 return -EINVAL;
5785 }
5786
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005787 if ((!hdd_ipa->num_iface) &&
5788 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305789 hdd_ipa->activated_fw_pipe) &&
5790 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005791 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005792 /*
5793 * We disable WDI pipes directly here since
5794 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5795 * processed when unloading WLAN driver is in
5796 * progress
5797 */
5798 hdd_ipa_uc_disable_pipes(hdd_ipa);
5799 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305800 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005801 "NO INTF left but still pipe clean up");
5802 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5803 }
5804 }
5805
5806 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005807 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005808 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005809 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005810 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005811 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5812 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005813 }
Yun Parka37592b2016-06-11 17:10:28 -07005814
Yun Park8f289c82016-10-18 16:38:21 -07005815 hdd_ipa_cleanup_iface(adapter->ipa_context);
5816
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305817 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005818 break;
5819
5820 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005821 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005822 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005823 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305824 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005825 return 0;
5826 }
5827
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305828 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005829 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5830 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005831 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305832 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005833 "%s: STA ID %d found, not valid",
5834 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005835 return 0;
5836 }
Yun Park312f71a2015-12-08 10:22:42 -08005837
5838 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005839 if (hdd_ipa->sap_num_connected_sta == 0 &&
5840 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005841 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005842 hdd_ipa->sta_connected) {
5843 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005844 hdd_ipa_uc_offload_enable_disable(
5845 hdd_get_adapter(hdd_ipa->hdd_ctx,
5846 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005847 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005848 qdf_mutex_acquire(&hdd_ipa->event_lock);
5849 }
Yun Parka37592b2016-06-11 17:10:28 -07005850
Yun Park312f71a2015-12-08 10:22:42 -08005851 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5852 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305853 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005854 "%s: handle 1st con ret %d",
5855 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005856
5857 if (hdd_ipa_uc_sta_is_enabled(
5858 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005859 hdd_ipa->sta_connected) {
5860 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005861 hdd_ipa_uc_offload_enable_disable(
5862 hdd_get_adapter(
5863 hdd_ipa->hdd_ctx,
5864 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005865 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005866 } else {
5867 qdf_mutex_release(&hdd_ipa->event_lock);
5868 }
Yun Parka37592b2016-06-11 17:10:28 -07005869
Yun Park312f71a2015-12-08 10:22:42 -08005870 return ret;
5871 }
5872 }
5873
5874 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005875
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305876 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005877
5878 meta.msg_type = type;
5879 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5880 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305881 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005882
5883 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305884 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005885 "msg_ex allocation failed");
5886 return -ENOMEM;
5887 }
5888 strlcpy(msg_ex->name, adapter->dev->name,
5889 IPA_RESOURCE_NAME_MAX);
5890 msg_ex->num_of_attribs = 1;
5891 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5892 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5893 msg_ex->attribs[0].offset =
5894 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5895 } else {
5896 msg_ex->attribs[0].offset =
5897 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5898 }
5899 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5900 IPA_MAC_ADDR_SIZE);
5901
5902 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5903
5904 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005905 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305906 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305907 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005908 return ret;
5909 }
5910 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005911 return ret;
5912
5913 case WLAN_CLIENT_DISCONNECT:
5914 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005915 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005916 "%s: IPA UC OFFLOAD NOT ENABLED",
5917 msg_ex->name);
5918 return 0;
5919 }
5920
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305921 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005922 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005923 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305924 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005925 "%s: STA ID %d NOT found, not valid",
5926 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005927 return 0;
5928 }
5929 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005930
Yun Park9b5030f2016-11-08 12:02:37 -08005931 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005932 if (!hdd_ipa->sap_num_connected_sta &&
5933 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005934 if ((false == hdd_ipa->resource_unloading)
5935 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305936 hdd_ipa->activated_fw_pipe) &&
5937 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005938 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5939 }
5940
Yun Park8f289c82016-10-18 16:38:21 -07005941 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005942
5943 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5944 hdd_ipa->sta_connected)
5945 hdd_ipa_uc_offload_enable_disable(
5946 hdd_get_adapter(hdd_ipa->hdd_ctx,
5947 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005948 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005949 } else {
5950 qdf_mutex_release(&hdd_ipa->event_lock);
5951 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005952 break;
5953
5954 default:
5955 return 0;
5956 }
5957
5958 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305959 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005960 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305961 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005962 return -ENOMEM;
5963 }
5964
5965 meta.msg_type = type;
5966 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5967 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5968
Srinivas Girigowda97852372017-03-06 16:52:59 -08005969 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005970 msg->name, meta.msg_type);
5971
5972 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5973
5974 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005975 hdd_err("%s: Evt: %d fail:%d",
5976 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305977 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005978 return ret;
5979 }
5980
5981 hdd_ipa->stats.num_send_msg++;
5982
5983end:
5984 return ret;
5985}
5986
5987/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005988 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005989 * @adapter: adapter upon which the event was received
5990 * @sta_id: station id for the event
5991 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5992 * @mac_address: MAC address associated with the event
5993 *
5994 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5995 *
5996 * Return: 0 on success, negative errno value on error
5997 */
5998int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
5999 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
6000{
6001 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006002 int ret = 0;
6003
6004 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07006005
Leo Changa202b522016-10-14 16:13:50 -07006006 /* Data path offload only support for STA and SAP mode */
6007 if ((QDF_STA_MODE == adapter->device_mode) ||
6008 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006009 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07006010
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006011 cds_ssr_unprotect(__func__);
6012
6013 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07006014}
6015
6016/**
6017 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
6018 * @hdd_ipa: Global HDD IPA context
6019 *
6020 * Return: None
6021 */
6022static void
6023hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
6024{
6025 unsigned int pending_event_count;
6026 struct ipa_uc_pending_event *pending_event = NULL;
6027
6028 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08006029 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07006030 "%s, Pending Event Count %d", __func__, pending_event_count);
6031 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08006032 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07006033 "%s, No Pending Event", __func__);
6034 return;
6035 }
6036
6037 qdf_list_remove_front(&hdd_ipa->pending_event,
6038 (qdf_list_node_t **)&pending_event);
6039 while (pending_event != NULL) {
6040 __hdd_ipa_wlan_evt(pending_event->adapter,
6041 pending_event->type,
6042 pending_event->sta_id,
6043 pending_event->mac_addr);
6044 qdf_mem_free(pending_event);
6045 pending_event = NULL;
6046 qdf_list_remove_front(&hdd_ipa->pending_event,
6047 (qdf_list_node_t **)&pending_event);
6048 }
6049}
6050
6051/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006052 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
6053 * @state: IPA RM state value
6054 *
6055 * Return: ASCII string representing the IPA RM state
6056 */
6057static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
6058{
6059 switch (state) {
6060 case HDD_IPA_RM_RELEASED:
6061 return "RELEASED";
6062 case HDD_IPA_RM_GRANT_PENDING:
6063 return "GRANT_PENDING";
6064 case HDD_IPA_RM_GRANTED:
6065 return "GRANTED";
6066 }
6067
6068 return "UNKNOWN";
6069}
6070
6071/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006072 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006073 * @hdd_ctx: HDD global context
6074 *
6075 * Allocate hdd_ipa resources, ipa pipe resource and register
6076 * wlan interface with IPA module.
6077 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306078 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006079 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006080static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006081{
6082 struct hdd_ipa_priv *hdd_ipa = NULL;
6083 int ret, i;
6084 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08006085 struct ol_txrx_pdev_t *pdev = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006086
6087 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306088 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006089
Yun Parkbaa62862017-01-18 13:43:34 -08006090 ENTER();
6091
6092 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07006093 if (!pdev) {
6094 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
6095 goto fail_return;
6096 }
6097
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306098 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006099 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306100 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08006101 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006102 }
6103
6104 hdd_ctx->hdd_ipa = hdd_ipa;
6105 ghdd_ipa = hdd_ipa;
6106 hdd_ipa->hdd_ctx = hdd_ctx;
6107 hdd_ipa->num_iface = 0;
6108
6109 /* Create the interface context */
6110 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6111 iface_context = &hdd_ipa->iface_context[i];
6112 iface_context->hdd_ipa = hdd_ipa;
6113 iface_context->cons_client =
6114 hdd_ipa_adapter_2_client[i].cons_client;
6115 iface_context->prod_client =
6116 hdd_ipa_adapter_2_client[i].prod_client;
6117 iface_context->iface_id = i;
6118 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306119 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08006120 }
6121 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08006122 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
6123 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006124 }
6125
Leo Chang69c39692016-10-12 20:11:12 -07006126 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306127 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006128 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05306129 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08006130 qdf_list_create(&hdd_ipa->pending_event, 1000);
6131 qdf_mutex_create(&hdd_ipa->event_lock);
6132 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006133
6134 ret = hdd_ipa_setup_rm(hdd_ipa);
6135 if (ret)
6136 goto fail_setup_rm;
6137
6138 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
6139 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306140 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006141 hdd_ipa->sap_num_connected_sta = 0;
6142 hdd_ipa->ipa_tx_packets_diff = 0;
6143 hdd_ipa->ipa_rx_packets_diff = 0;
6144 hdd_ipa->ipa_p_tx_packets = 0;
6145 hdd_ipa->ipa_p_rx_packets = 0;
6146 hdd_ipa->resource_loading = false;
6147 hdd_ipa->resource_unloading = false;
6148 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07006149 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08006150 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006151 /* Setup IPA sys_pipe for MCC */
6152 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
6153 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6154 if (ret)
6155 goto fail_create_sys_pipe;
6156 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08006157 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
6158 goto fail_create_sys_pipe;
Manikandan Mohan2e803a02017-02-14 14:57:53 -08006159
6160 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6161 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
6162 hdd_ipa_uc_fw_op_event_handler);
6163 hdd_ipa->uc_op_work[i].msg = NULL;
6164 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006165 } else {
6166 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6167 if (ret)
6168 goto fail_create_sys_pipe;
6169 }
6170
Yun Parkbaa62862017-01-18 13:43:34 -08006171 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306172 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006173
6174fail_create_sys_pipe:
6175 hdd_ipa_destroy_rm_resource(hdd_ipa);
6176fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306177 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306178 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08006179 hdd_ctx->hdd_ipa = NULL;
6180 ghdd_ipa = NULL;
6181fail_return:
Yun Parkbaa62862017-01-18 13:43:34 -08006182 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306183 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006184}
6185
6186/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006187 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
6188 * @hdd_ctx: HDD global context
6189 *
6190 * Allocate hdd_ipa resources, ipa pipe resource and register
6191 * wlan interface with IPA module.
6192 *
6193 * Return: QDF_STATUS enumeration
6194 */
6195QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
6196{
6197 QDF_STATUS ret;
6198
6199 cds_ssr_protect(__func__);
6200 ret = __hdd_ipa_init(hdd_ctx);
6201 cds_ssr_unprotect(__func__);
6202
6203 return ret;
6204}
6205
Arun Khandavallicc544b32017-01-30 19:52:16 +05306206
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006207/**
Yun Parkf19e07d2015-11-20 11:34:27 -08006208 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
6209 * @hdd_ipa: pointer to HDD IPA struct
6210 *
6211 * Return: none
6212 */
Jeff Johnsond7720632016-10-05 16:04:32 -07006213static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08006214{
6215 struct ipa_uc_pending_event *pending_event = NULL;
6216
Anurag Chouhanffb21542016-02-17 14:33:03 +05306217 while (qdf_list_remove_front(&hdd_ipa->pending_event,
6218 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306219 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08006220 }
6221
Anurag Chouhanffb21542016-02-17 14:33:03 +05306222 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08006223}
6224
6225/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006226 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006227 * @hdd_ctx: HDD global context
6228 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306229 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006230 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006231static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006232{
6233 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
6234 int i;
6235 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05306236 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006237 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
6238
6239 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306240 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006241
6242 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
6243 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
6244 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6245 }
6246
6247 /* Teardown IPA sys_pipe for MCC */
6248 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
6249 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6250
6251 hdd_ipa_destroy_rm_resource(hdd_ipa);
6252
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006253 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006254
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306255 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006256
Nirav Shahcbc6d722016-03-01 16:24:53 +05306257 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
6258 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306259 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006260
6261 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07006262 if (pm_tx_cb->ipa_tx_desc)
6263 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006264
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306265 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006266 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306267 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006268
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306269 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006270 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006271
6272 /* destory the interface lock */
6273 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6274 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306275 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006276 }
6277
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006278 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08006279 if (ipa_uc_dereg_rdyCB())
6280 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
6281 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006282 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306283 qdf_mutex_destroy(&hdd_ipa->event_lock);
6284 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08006285 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006286
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006287 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6288 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
6289 hdd_ipa->uc_op_work[i].msg = NULL;
6290 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006291 }
6292
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306293 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006294 hdd_ctx->hdd_ipa = NULL;
6295
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306296 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006297}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006298
6299/**
6300 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
6301 * @hdd_ctx: HDD global context
6302 *
6303 * Return: QDF_STATUS enumeration
6304 */
6305QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
6306{
6307 QDF_STATUS ret;
6308
6309 cds_ssr_protect(__func__);
6310 ret = __hdd_ipa_cleanup(hdd_ctx);
6311 cds_ssr_unprotect(__func__);
6312
6313 return ret;
6314}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006315#endif /* IPA_OFFLOAD */