blob: 15f3ae5d34bedbf5e6b8e9498992d45bd63d8cfd [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 */
Dustin Brown0bec9a92017-08-17 15:44:34 -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"
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -080061#include "wlan_policy_mgr_api.h"
62
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080063#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080064#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
Yun Parkb4f591d2017-03-29 15:51:01 -070065
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080066#define HDD_IPA_UC_NUM_WDI_PIPE 2
67#define HDD_IPA_UC_MAX_PENDING_EVENT 33
68
69#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
70#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
71#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
72#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
73
74#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
75#define HDD_IPA_MAX_IFACE 3
76#define HDD_IPA_MAX_SYSBAM_PIPE 4
Yun Parkb4f591d2017-03-29 15:51:01 -070077
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080078#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
79#define HDD_IPA_ENABLE_MASK BIT(0)
80#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
81#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
82#define HDD_IPA_RM_ENABLE_MASK BIT(3)
83#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
84#define HDD_IPA_UC_ENABLE_MASK BIT(5)
85#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
86#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
87
Yun Parkf19e07d2015-11-20 11:34:27 -080088#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
89
tfyu0380a972017-07-13 18:19:37 +080090#define IPA_WLAN_RX_SOFTIRQ_THRESH 16
91
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -070092enum hdd_ipa_uc_op_code {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080093 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
94 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
95 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
96 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
97 HDD_IPA_UC_OPCODE_STATS = 4,
Yun Park637d6482016-10-05 10:51:33 -070098#ifdef FEATURE_METERING
99 HDD_IPA_UC_OPCODE_SHARING_STATS = 5,
100 HDD_IPA_UC_OPCODE_QUOTA_RSP = 6,
101 HDD_IPA_UC_OPCODE_QUOTA_IND = 7,
102#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800103 HDD_IPA_UC_OPCODE_UC_READY = 8,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800104 /* keep this last */
105 HDD_IPA_UC_OPCODE_MAX
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700106};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800107
108/**
109 * enum - Reason codes for stat query
110 *
111 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
112 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
113 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800114 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800115 */
116enum {
117 HDD_IPA_UC_STAT_REASON_NONE,
118 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -0800119 HDD_IPA_UC_STAT_REASON_BW_CAL,
120 HDD_IPA_UC_STAT_REASON_DUMP_INFO
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800121};
122
123/**
124 * enum hdd_ipa_rm_state - IPA resource manager state
125 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
126 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
127 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
128 */
129enum hdd_ipa_rm_state {
130 HDD_IPA_RM_RELEASED,
131 HDD_IPA_RM_GRANT_PENDING,
132 HDD_IPA_RM_GRANTED,
133};
134
135struct llc_snap_hdr {
136 uint8_t dsap;
137 uint8_t ssap;
138 uint8_t resv[4];
139 __be16 eth_type;
140} __packed;
141
Leo Chang3bc8fed2015-11-13 10:59:47 -0800142/**
143 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
144 * @eth: ether II header
145 * @llc_snap: LLC snap header
146 *
147 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800148struct hdd_ipa_tx_hdr {
149 struct ethhdr eth;
150 struct llc_snap_hdr llc_snap;
151} __packed;
152
Leo Chang3bc8fed2015-11-13 10:59:47 -0800153/**
154 * struct frag_header - fragment header type registered to IPA hardware
155 * @length: fragment length
156 * @reserved1: Reserved not used
157 * @reserved2: Reserved not used
158 *
159 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800160struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800161 uint16_t length;
162 uint32_t reserved1;
163 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164} __packed;
165
Leo Chang3bc8fed2015-11-13 10:59:47 -0800166/**
167 * struct ipa_header - ipa header type registered to IPA hardware
168 * @vdev_id: vdev id
169 * @reserved: Reserved not used
170 *
171 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800172struct ipa_header {
173 uint32_t
174 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
175 reserved:24;
176} __packed;
177
Leo Chang3bc8fed2015-11-13 10:59:47 -0800178/**
179 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
180 * @frag_hd: fragment header
181 * @ipa_hd: ipa header
182 * @eth: ether II header
183 *
184 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185struct hdd_ipa_uc_tx_hdr {
186 struct frag_header frag_hd;
187 struct ipa_header ipa_hd;
188 struct ethhdr eth;
189} __packed;
190
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800191/**
192 * struct hdd_ipa_cld_hdr - IPA CLD Header
193 * @reserved: reserved fields
194 * @iface_id: interface ID
195 * @sta_id: Station ID
196 *
197 * Packed 32-bit structure
198 * +----------+----------+--------------+--------+
199 * | Reserved | QCMAP ID | interface id | STA ID |
200 * +----------+----------+--------------+--------+
201 */
202struct hdd_ipa_cld_hdr {
203 uint8_t reserved[2];
204 uint8_t iface_id;
205 uint8_t sta_id;
206} __packed;
207
208struct hdd_ipa_rx_hdr {
209 struct hdd_ipa_cld_hdr cld_hdr;
210 struct ethhdr eth;
211} __packed;
212
213struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700214 bool exception;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700215 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216 struct hdd_ipa_iface_context *iface_context;
217 struct ipa_rx_data *ipa_tx_desc;
218};
219
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800220struct hdd_ipa_sys_pipe {
221 uint32_t conn_hdl;
222 uint8_t conn_hdl_valid;
223 struct ipa_sys_connect_params ipa_sys_params;
224};
225
226struct hdd_ipa_iface_stats {
227 uint64_t num_tx;
228 uint64_t num_tx_drop;
229 uint64_t num_tx_err;
230 uint64_t num_tx_cac_drop;
231 uint64_t num_rx_prefilter;
232 uint64_t num_rx_ipa_excep;
233 uint64_t num_rx_recv;
234 uint64_t num_rx_recv_mul;
235 uint64_t num_rx_send_desc_err;
236 uint64_t max_rx_mul;
237};
238
239struct hdd_ipa_priv;
240
241struct hdd_ipa_iface_context {
242 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700243 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800244 void *tl_context;
245
246 enum ipa_client_type cons_client;
247 enum ipa_client_type prod_client;
248
249 uint8_t iface_id; /* This iface ID */
250 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530251 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800252 uint32_t ifa_address;
253 struct hdd_ipa_iface_stats stats;
254};
255
256struct hdd_ipa_stats {
257 uint32_t event[IPA_WLAN_EVENT_MAX];
258 uint64_t num_send_msg;
259 uint64_t num_free_msg;
260
261 uint64_t num_rm_grant;
262 uint64_t num_rm_release;
263 uint64_t num_rm_grant_imm;
264 uint64_t num_cons_perf_req;
265 uint64_t num_prod_perf_req;
266
267 uint64_t num_rx_drop;
268 uint64_t num_rx_ipa_tx_dp;
269 uint64_t num_rx_ipa_splice;
270 uint64_t num_rx_ipa_loop;
271 uint64_t num_rx_ipa_tx_dp_err;
272 uint64_t num_rx_ipa_write_done;
273 uint64_t num_max_ipa_tx_mul;
274 uint64_t num_rx_ipa_hw_maxed_out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800275
Yun Park52b2b992016-09-22 15:49:51 -0700276 uint64_t num_tx_desc_q_cnt;
277 uint64_t num_tx_desc_error;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800278 uint64_t num_tx_comp_cnt;
279 uint64_t num_tx_queued;
280 uint64_t num_tx_dequeued;
281 uint64_t num_max_pm_queue;
282
283 uint64_t num_freeq_empty;
284 uint64_t num_pri_freeq_empty;
285 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800286 uint64_t num_tx_fwd_ok;
287 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800288};
289
290struct ipa_uc_stas_map {
291 bool is_reserved;
292 uint8_t sta_id;
293};
294struct op_msg_type {
295 uint8_t msg_t;
296 uint8_t rsvd;
297 uint16_t op_code;
298 uint16_t len;
299 uint16_t rsvd_snd;
300};
301
302struct ipa_uc_fw_stats {
303 uint32_t tx_comp_ring_base;
304 uint32_t tx_comp_ring_size;
305 uint32_t tx_comp_ring_dbell_addr;
306 uint32_t tx_comp_ring_dbell_ind_val;
307 uint32_t tx_comp_ring_dbell_cached_val;
308 uint32_t tx_pkts_enqueued;
309 uint32_t tx_pkts_completed;
310 uint32_t tx_is_suspend;
311 uint32_t tx_reserved;
312 uint32_t rx_ind_ring_base;
313 uint32_t rx_ind_ring_size;
314 uint32_t rx_ind_ring_dbell_addr;
315 uint32_t rx_ind_ring_dbell_ind_val;
316 uint32_t rx_ind_ring_dbell_ind_cached_val;
317 uint32_t rx_ind_ring_rdidx_addr;
318 uint32_t rx_ind_ring_rd_idx_cached_val;
319 uint32_t rx_refill_idx;
320 uint32_t rx_num_pkts_indicated;
321 uint32_t rx_buf_refilled;
322 uint32_t rx_num_ind_drop_no_space;
323 uint32_t rx_num_ind_drop_no_buf;
324 uint32_t rx_is_suspend;
325 uint32_t rx_reserved;
326};
327
328struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530329 qdf_list_node_t node;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700330 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800331 enum ipa_wlan_event type;
332 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530333 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800334};
335
336/**
337 * struct uc_rm_work_struct
338 * @work: uC RM work
339 * @event: IPA RM event
340 */
341struct uc_rm_work_struct {
342 struct work_struct work;
343 enum ipa_rm_event event;
344};
345
346/**
347 * struct uc_op_work_struct
348 * @work: uC OP work
349 * @msg: OP message
350 */
351struct uc_op_work_struct {
352 struct work_struct work;
353 struct op_msg_type *msg;
354};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800355
356/**
357 * struct uc_rt_debug_info
358 * @time: system time
359 * @ipa_excep_count: IPA exception packet count
360 * @rx_drop_count: IPA Rx drop packet count
361 * @net_sent_count: IPA Rx packet sent to network stack count
362 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800363 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800364 * @tx_fwd_count: IPA Tx forward packet count
365 * @rx_destructor_call: IPA Rx packet destructor count
366 */
367struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530368 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800369 uint64_t ipa_excep_count;
370 uint64_t rx_drop_count;
371 uint64_t net_sent_count;
372 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800373 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800374 uint64_t tx_fwd_count;
375 uint64_t rx_destructor_call;
376};
377
Yun Park637d6482016-10-05 10:51:33 -0700378#ifdef FEATURE_METERING
379struct ipa_uc_sharing_stats {
380 uint64_t ipv4_rx_packets;
381 uint64_t ipv4_rx_bytes;
382 uint64_t ipv6_rx_packets;
383 uint64_t ipv6_rx_bytes;
384 uint64_t ipv4_tx_packets;
385 uint64_t ipv4_tx_bytes;
386 uint64_t ipv6_tx_packets;
387 uint64_t ipv6_tx_bytes;
388};
389
390struct ipa_uc_quota_rsp {
391 uint8_t success;
392 uint8_t reserved[3];
393 uint32_t quota_lo; /* quota limit low bytes */
394 uint32_t quota_hi; /* quota limit high bytes */
395};
396
397struct ipa_uc_quota_ind {
398 uint64_t quota_bytes; /* quota limit in bytes */
399};
400#endif
401
Yun Park52b2b992016-09-22 15:49:51 -0700402/**
403 * struct hdd_ipa_tx_desc
404 * @link: link to list head
405 * @priv: pointer to priv list entry
406 * @id: Tx desc idex
407 * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor
408 */
409struct hdd_ipa_tx_desc {
410 struct list_head link;
411 void *priv;
412 uint32_t id;
413 struct ipa_rx_data *ipa_tx_desc_ptr;
414};
415
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800416struct hdd_ipa_priv {
417 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
418 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
419 uint8_t num_iface;
420 enum hdd_ipa_rm_state rm_state;
421 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530422 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423 * APIs as it is taken care gracefully. Without this, kernel would throw
424 * an warning if spin_lock_bh is used while IRQ is disabled
425 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530426 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800427 struct uc_rm_work_struct uc_rm_work;
428 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530429 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800430 struct delayed_work wake_lock_work;
431 bool wake_lock_released;
432
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800433 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530434 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800435 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530436 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800437 bool suspended;
438
Yun Park52b2b992016-09-22 15:49:51 -0700439 qdf_spinlock_t q_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800440
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800441 struct list_head pend_desc_head;
Yun Park52b2b992016-09-22 15:49:51 -0700442 struct hdd_ipa_tx_desc *tx_desc_list;
443 struct list_head free_tx_desc_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800444
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700445 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800446
447 struct dentry *debugfs_dir;
448 struct hdd_ipa_stats stats;
449
450 struct notifier_block ipv4_notifier;
451 uint32_t curr_prod_bw;
452 uint32_t curr_cons_bw;
453
454 uint8_t activated_fw_pipe;
455 uint8_t sap_num_connected_sta;
456 uint8_t sta_connected;
457 uint32_t tx_pipe_handle;
458 uint32_t rx_pipe_handle;
459 bool resource_loading;
460 bool resource_unloading;
461 bool pending_cons_req;
462 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530463 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530464 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700465 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800466 uint32_t ipa_tx_packets_diff;
467 uint32_t ipa_rx_packets_diff;
468 uint32_t ipa_p_tx_packets;
469 uint32_t ipa_p_rx_packets;
470 uint32_t stat_req_reason;
471 uint64_t ipa_tx_forward;
472 uint64_t ipa_rx_discard;
473 uint64_t ipa_rx_net_send_count;
474 uint64_t ipa_rx_internel_drop_count;
475 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530476 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
478 unsigned int rt_buf_fill_index;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800479 struct ipa_wdi_in_params cons_pipe_in;
480 struct ipa_wdi_in_params prod_pipe_in;
481 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800482 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530483 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530484 qdf_mutex_t rt_debug_lock;
485 qdf_mutex_t ipa_lock;
Yun Parkb4f591d2017-03-29 15:51:01 -0700486
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800487 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
488 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Yun Park637d6482016-10-05 10:51:33 -0700489#ifdef FEATURE_METERING
490 struct ipa_uc_sharing_stats ipa_sharing_stats;
491 struct ipa_uc_quota_rsp ipa_quota_rsp;
492 struct ipa_uc_quota_ind ipa_quota_ind;
493 struct completion ipa_uc_sharing_stats_comp;
494 struct completion ipa_uc_set_quota_comp;
495#endif
Yun Park777d7242017-03-30 15:38:33 -0700496 struct completion ipa_resource_comp;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800497};
498
Leo Changcc923e22016-06-16 15:29:03 -0700499#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
500#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
502#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
503#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
504#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
505#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700506#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
507 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800508
509#define HDD_IPA_GET_IFACE_ID(_data) \
510 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
511
512#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530513 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800514 "%s:%d: "fmt, __func__, __LINE__, ## args)
515
Govind Singhb6a89772016-08-12 11:23:35 +0530516#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
517 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
518 "%s:%d: "fmt, __func__, __LINE__, ## args)
519
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800520#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
521 do { \
Yun Parkec845302016-12-15 09:22:57 -0800522 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \
523 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800524 } while (0)
525
526#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
527 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
528
529#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
Jeff Johnsond5ba8a62017-09-30 14:30:53 -0700530 (hdd_ipa)->ipa_rx_internel_drop_count++
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800531#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
Jeff Johnsond5ba8a62017-09-30 14:30:53 -0700532 (hdd_ipa)->ipa_rx_net_send_count++
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800533#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
534
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700535#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)
Leo Chang63d73612016-10-18 18:09:43 -0700536#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800537#else
538/* Do nothing */
Leo Chang63d73612016-10-18 18:09:43 -0700539#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700540#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800541
Yun Park0dad1002017-07-14 14:57:01 -0700542#define HDD_IPA_DBG_DUMP_RX_LEN 84
Yun Parkb187d542016-11-14 18:10:04 -0800543#define HDD_IPA_DBG_DUMP_TX_LEN 48
544
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545static struct hdd_ipa_adapter_2_client {
546 enum ipa_client_type cons_client;
547 enum ipa_client_type prod_client;
548} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
549 {
550 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
551 }, {
552 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
553 }, {
554 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
555 },
556};
557
Yun Park637d6482016-10-05 10:51:33 -0700558#ifdef FEATURE_METERING
559#define IPA_UC_SHARING_STATES_WAIT_TIME 500
560#define IPA_UC_SET_QUOTA_WAIT_TIME 500
561#endif
562
Yun Park777d7242017-03-30 15:38:33 -0700563#define IPA_RESOURCE_COMP_WAIT_TIME 100
564
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800565static struct hdd_ipa_priv *ghdd_ipa;
566
567/* Local Function Prototypes */
568static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
569 unsigned long data);
570static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
571 unsigned long data);
Yun Parkb4f591d2017-03-29 15:51:01 -0700572#ifdef FEATURE_METERING
573static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
574 void *data);
575#else
576static void hdd_ipa_wdi_meter_notifier_cb(void);
577#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800578static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800579
580static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700581static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800582
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800583#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
584 defined(IPA_CLIENT_IS_MHI_CONS))
585/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800586 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
587 * @priv_ctxt: hdd ipa local context
588 *
589 * Will be called by IPA context.
590 * It's atomic context, then should be scheduled to kworker thread
591 *
592 * Return: None
593 */
594static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
595{
596 struct hdd_ipa_priv *hdd_ipa;
597 struct op_msg_type *msg;
598 struct uc_op_work_struct *uc_op_work;
599
600 if (priv_ctxt == NULL) {
601 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
602 return;
603 }
604
605 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
606 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
607 if (!msg) {
608 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
609 return;
610 }
611
612 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
613
614 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
615
616 /* When the same uC OPCODE is already pended, just return */
617 if (uc_op_work->msg)
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530618 goto done;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800619
620 uc_op_work->msg = msg;
621 schedule_work(&uc_op_work->work);
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530622
jiadd91a6842017-08-01 14:46:02 +0800623 /* work handler will free the msg buffer */
624 return;
625
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530626done:
627 qdf_mem_free(msg);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800628}
629
630/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800631 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
632 * @ctrl: WDI control value
633 *
634 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
635 *
636 * Return: 0 on message send to ipa, -1 on failure
637 */
638static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
639{
640 struct ipa_msg_meta meta;
641 struct ipa_wlan_msg *ipa_msg;
642 int ret = 0;
643
644 /* WDI enable message to IPA */
645 meta.msg_len = sizeof(*ipa_msg);
646 ipa_msg = qdf_mem_malloc(meta.msg_len);
647 if (ipa_msg == NULL) {
648 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
649 "msg allocation failed");
650 return -ENOMEM;
651 }
652
653 if (ctrl == true)
654 meta.msg_type = WLAN_WDI_ENABLE;
655 else
656 meta.msg_type = WLAN_WDI_DISABLE;
657
Srinivas Girigowda97852372017-03-06 16:52:59 -0800658 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800659 "ipa_send_msg(Evt:%d)", meta.msg_type);
660 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
661 if (ret) {
662 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
663 "ipa_send_msg(Evt:%d)-fail=%d",
664 meta.msg_type, ret);
665 qdf_mem_free(ipa_msg);
666 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800667 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800668}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800669
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800670/**
671 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
672 * @hdd_ipa: HDD IPA local context
673 *
674 * Register IPA UC ready callback function to IPA kernel driver
675 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
676 * open WDI pipe after WLAN driver loading finished
677 *
678 * Return: 0 Success
679 * -EPERM Registration fail
680 */
681static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
682{
683 struct ipa_wdi_uc_ready_params uc_ready_param;
684 int ret = 0;
685
686 hdd_ipa->uc_loaded = false;
687 uc_ready_param.priv = (void *)hdd_ipa;
688 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
689 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
690 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
691 "UC Ready CB register fail");
692 return -EPERM;
693 }
694 if (true == uc_ready_param.is_uC_ready) {
Srinivas Girigowda2b5d47c2017-03-29 00:28:46 -0700695 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800696 hdd_ipa->uc_loaded = true;
697 } else {
698 ret = hdd_ipa_uc_send_wdi_control_msg(false);
699 }
700
701 return ret;
702}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800703#else
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800704static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
705{
706 hdd_ipa->uc_loaded = true;
707 return 0;
708}
709
710static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
711{
712 return 0;
713}
714#endif
715
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800716/**
717 * hdd_ipa_is_enabled() - Is IPA enabled?
718 * @hdd_ctx: Global HDD context
719 *
720 * Return: true if IPA is enabled, false otherwise
721 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700722bool hdd_ipa_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800723{
724 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
725}
726
727/**
728 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
729 * @hdd_ctx: Global HDD context
730 *
731 * Return: true if IPA uC offload is enabled, false otherwise
732 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700733bool hdd_ipa_uc_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800734{
735 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
736}
737
738/**
739 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
740 * @hdd_ctx: Global HDD context
741 *
742 * Return: true if STA mode IPA uC offload is enabled, false otherwise
743 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700744static inline bool hdd_ipa_uc_sta_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745{
746 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
747}
748
749/**
Guolei Bianca144d82016-11-10 11:07:42 +0800750 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
751 * @hdd_ipa: Global HDD IPA context
752 *
753 * Return: None
754 */
Guolei Bianca144d82016-11-10 11:07:42 +0800755static inline void hdd_ipa_uc_sta_reset_sta_connected(
756 struct hdd_ipa_priv *hdd_ipa)
757{
Yun Park637d6482016-10-05 10:51:33 -0700758 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800759 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700760 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800761}
Guolei Bianca144d82016-11-10 11:07:42 +0800762
763/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800764 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
765 * @hdd_ipa: Global HDD IPA context
766 *
767 * Return: true if pre-filter is enabled, otherwise false
768 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700769static inline bool hdd_ipa_is_pre_filter_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800770{
771 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
772 HDD_IPA_PRE_FILTER_ENABLE_MASK);
773}
774
775/**
776 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
777 * @hdd_ipa: Global HDD IPA context
778 *
779 * Return: true if IPv6 is enabled, otherwise false
780 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700781static inline bool hdd_ipa_is_ipv6_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800782{
783 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
784}
785
786/**
787 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
788 * @hdd_ipa: Global HDD IPA context
789 *
790 * Return: true if resource manager is enabled, otherwise false
791 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700792static inline bool hdd_ipa_is_rm_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793{
794 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
795}
796
797/**
798 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
799 * @hdd_ipa: Global HDD IPA context
800 *
801 * Return: true if resource manager is enabled, otherwise false
802 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700803static inline bool hdd_ipa_is_rt_debugging_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800804{
805 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
806}
807
808/**
809 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
810 * @hdd_ipa: Global HDD IPA context
811 *
812 * Return: true if clock scaling is enabled, otherwise false
813 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700814static inline bool hdd_ipa_is_clk_scaling_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800815{
816 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
817 HDD_IPA_CLK_SCALING_ENABLE_MASK |
818 HDD_IPA_RM_ENABLE_MASK);
819}
820
821/**
822 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
823 * @ctext: pointer to hdd context.
824 *
825 * If rt debug enabled, periodically called, and fill debug buffer
826 *
827 * Return: none
828 */
829static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
830{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700831 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800832 struct hdd_ipa_priv *hdd_ipa;
833 struct uc_rt_debug_info *dump_info = NULL;
834
835 if (wlan_hdd_validate_context(hdd_ctx))
836 return;
837
838 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700839 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840 return;
841 }
842
843 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
844
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530845 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800846 dump_info = &hdd_ipa->rt_bug_buffer[
847 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
848
Deepthi Gowri6acee342016-10-28 15:00:38 +0530849 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800850 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
851 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
852 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800853 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800854 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
855 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800856 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
857 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530858 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859
Anurag Chouhan210db072016-02-22 18:42:15 +0530860 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800861 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
862}
863
864/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700865 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 * @hdd_ctx: pointer to hdd context.
867 *
868 * If rt debug enabled, dump debug buffer contents based on requirement
869 *
870 * Return: none
871 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700872static void __hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873{
874 struct hdd_ipa_priv *hdd_ipa;
875 unsigned int dump_count;
876 unsigned int dump_index;
877 struct uc_rt_debug_info *dump_info = NULL;
878
879 if (wlan_hdd_validate_context(hdd_ctx))
880 return;
881
882 hdd_ipa = hdd_ctx->hdd_ipa;
883 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700884 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800885 return;
886 }
887
Chris Guo1751acf2017-07-03 14:09:01 +0800888 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
889 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
890 "%s: IPA RT debug is not enabled", __func__);
891 return;
892 }
893
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530894 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800895 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530896 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800897 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530899 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800900 for (dump_count = 0;
901 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
902 dump_count++) {
903 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
904 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
905 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530906 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530907 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800908 dump_info->time, dump_info->ipa_excep_count,
909 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800910 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800911 dump_info->rx_destructor_call,
912 dump_info->rx_discard_count);
913 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530914 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530915 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
917}
918
919/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700920 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
921 * __hdd_ipa_uc_rt_debug_host_dump
922 * @hdd_ctx: pointer to hdd context.
923 *
924 * If rt debug enabled, dump debug buffer contents based on requirement
925 *
926 * Return: none
927 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700928void hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700929{
930 cds_ssr_protect(__func__);
931 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
932 cds_ssr_unprotect(__func__);
933}
934
935/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800936 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
937 * @ctext: pointer to hdd context.
938 *
939 * periodically called by timer expire
940 * will try to alloc dummy memory and detect out of memory condition
941 * if out of memory detected, dump wlan-ipa stats
942 *
943 * Return: none
944 */
945static void hdd_ipa_uc_rt_debug_handler(void *ctext)
946{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700947 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700948 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949 void *dummy_ptr = NULL;
950
951 if (wlan_hdd_validate_context(hdd_ctx))
952 return;
953
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700954 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
955
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800956 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700957 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
958 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800959 return;
960 }
961
962 /* Allocate dummy buffer periodically and free immediately. this will
963 * proactively detect OOM and if allocation fails dump ipa stats
964 */
965 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
966 GFP_KERNEL | GFP_ATOMIC);
967 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800968 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
969 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -0700970 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
971 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800972 } else {
973 kfree(dummy_ptr);
974 }
975
Anurag Chouhan210db072016-02-22 18:42:15 +0530976 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800977 HDD_IPA_UC_RT_DEBUG_PERIOD);
978}
979
980/**
Yun Parkb187d542016-11-14 18:10:04 -0800981 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800982 * @skb: packet pinter
983 *
984 * when free data packet, will be invoked by wlan client and will increase
985 * free counter
986 *
987 * Return: none
988 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700989static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990{
991 if (!ghdd_ipa) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700992 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "invalid hdd context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800993 return;
994 }
995
996 ghdd_ipa->ipa_rx_destructor_count++;
997}
998
999/**
Yun Parkb187d542016-11-14 18:10:04 -08001000 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001001 * @hdd_ctx: hdd main context
1002 *
1003 * free all rt debugging resources
1004 *
1005 * Return: none
1006 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001007static void hdd_ipa_uc_rt_debug_deinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001008{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001009 struct hdd_ipa_priv *hdd_ipa;
1010
1011 if (wlan_hdd_validate_context(hdd_ctx))
1012 return;
1013
1014 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001015
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301016 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001017
1018 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001019 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1020 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001021 return;
1022 }
1023
Anurag Chouhan210db072016-02-22 18:42:15 +05301024 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001025 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1026 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1027 }
1028 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1029
1030 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301031 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1032 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001033 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301034 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035}
1036
1037/**
Yun Parkb187d542016-11-14 18:10:04 -08001038 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 * @hdd_ctx: hdd main context
1040 *
1041 * alloc and initialize all rt debugging resources
1042 *
1043 * Return: none
1044 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001045static void hdd_ipa_uc_rt_debug_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001047 struct hdd_ipa_priv *hdd_ipa;
1048
Chris Guo1751acf2017-07-03 14:09:01 +08001049 if (wlan_hdd_validate_context_in_loading(hdd_ctx))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001050 return;
1051
1052 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001053
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301054 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001055 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301056 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057 sizeof(struct uc_rt_debug_info) *
1058 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1059 hdd_ipa->ipa_tx_forward = 0;
1060 hdd_ipa->ipa_rx_discard = 0;
1061 hdd_ipa->ipa_rx_net_send_count = 0;
1062 hdd_ipa->ipa_rx_internel_drop_count = 0;
1063 hdd_ipa->ipa_rx_destructor_count = 0;
1064
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 /* Reatime debug enable on feature enable */
1066 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001067 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1068 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069 return;
1070 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001071
1072 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1073 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1074 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1075 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1076
Anurag Chouhan210db072016-02-22 18:42:15 +05301077 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001078 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301079 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001080 HDD_IPA_UC_RT_DEBUG_PERIOD);
1081
1082}
1083
1084/**
Yun Parkb187d542016-11-14 18:10:04 -08001085 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1086 * @hdd_ipa: HDD IPA struct
1087 *
1088 * Dump entries in struct hdd_ipa
1089 *
1090 * Return: none
1091 */
1092static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1093{
1094 int i;
1095
1096 /* HDD IPA */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001097 hdd_info("==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001098 "num_iface: %d\n"
1099 "rm_state: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001100 "rm_lock: %pK\n"
1101 "uc_rm_work: %pK\n"
1102 "uc_op_work: %pK\n"
1103 "wake_lock: %pK\n"
1104 "wake_lock_work: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001105 "wake_lock_released: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001106 "tx_ref_cnt: %d\n"
1107 "pm_queue_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001108 "\thead: %pK\n"
1109 "\ttail: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001110 "\tqlen: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001111 "pm_work: %pK\n"
1112 "pm_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001113 "suspended: %d\n",
1114 hdd_ipa->num_iface,
1115 hdd_ipa->rm_state,
1116 &hdd_ipa->rm_lock,
1117 &hdd_ipa->uc_rm_work,
1118 &hdd_ipa->uc_op_work,
1119 &hdd_ipa->wake_lock,
1120 &hdd_ipa->wake_lock_work,
1121 hdd_ipa->wake_lock_released,
Yun Parkb187d542016-11-14 18:10:04 -08001122 hdd_ipa->tx_ref_cnt.counter,
1123 hdd_ipa->pm_queue_head.head,
1124 hdd_ipa->pm_queue_head.tail,
1125 hdd_ipa->pm_queue_head.qlen,
1126 &hdd_ipa->pm_work,
1127 &hdd_ipa->pm_lock,
1128 hdd_ipa->suspended);
Jeff Johnson36e74c42017-09-18 08:15:42 -07001129 hdd_err("\nq_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001130 "pend_desc_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001131 "\tnext: %pK\n"
1132 "\tprev: %pK\n"
1133 "hdd_ctx: %pK\n"
1134 "debugfs_dir: %pK\n"
1135 "stats: %pK\n"
1136 "ipv4_notifier: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001137 "curr_prod_bw: %d\n"
1138 "curr_cons_bw: %d\n"
1139 "activated_fw_pipe: %d\n"
1140 "sap_num_connected_sta: %d\n"
1141 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001142 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001143 hdd_ipa->pend_desc_head.next,
1144 hdd_ipa->pend_desc_head.prev,
1145 hdd_ipa->hdd_ctx,
1146 hdd_ipa->debugfs_dir,
1147 &hdd_ipa->stats,
1148 &hdd_ipa->ipv4_notifier,
1149 hdd_ipa->curr_prod_bw,
1150 hdd_ipa->curr_cons_bw,
1151 hdd_ipa->activated_fw_pipe,
1152 hdd_ipa->sap_num_connected_sta,
1153 (unsigned int)hdd_ipa->sta_connected
1154 );
Srinivas Girigowda97852372017-03-06 16:52:59 -08001155 hdd_info("\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001156 "rx_pipe_handle: 0x%x\n"
1157 "resource_loading: %d\n"
1158 "resource_unloading: %d\n"
1159 "pending_cons_req: %d\n"
1160 "pending_event----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001161 "\tanchor.next: %pK\n"
1162 "\tanchor.prev: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001163 "\tcount: %d\n"
1164 "\tmax_size: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001165 "event_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001166 "ipa_tx_packets_diff: %d\n"
1167 "ipa_rx_packets_diff: %d\n"
1168 "ipa_p_tx_packets: %d\n"
1169 "ipa_p_rx_packets: %d\n"
1170 "stat_req_reason: %d\n",
1171 hdd_ipa->tx_pipe_handle,
1172 hdd_ipa->rx_pipe_handle,
1173 hdd_ipa->resource_loading,
1174 hdd_ipa->resource_unloading,
1175 hdd_ipa->pending_cons_req,
1176 hdd_ipa->pending_event.anchor.next,
1177 hdd_ipa->pending_event.anchor.prev,
1178 hdd_ipa->pending_event.count,
1179 hdd_ipa->pending_event.max_size,
1180 &hdd_ipa->event_lock,
1181 hdd_ipa->ipa_tx_packets_diff,
1182 hdd_ipa->ipa_rx_packets_diff,
1183 hdd_ipa->ipa_p_tx_packets,
1184 hdd_ipa->ipa_p_rx_packets,
1185 hdd_ipa->stat_req_reason);
1186
Srinivas Girigowda97852372017-03-06 16:52:59 -08001187 hdd_info("assoc_stas_map([id]is_reserved/sta_id): ");
Yun Parkb187d542016-11-14 18:10:04 -08001188 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001189 hdd_info(" [%d]%d/%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001190 hdd_ipa->assoc_stas_map[i].is_reserved,
1191 hdd_ipa->assoc_stas_map[i].sta_id);
1192 }
1193}
1194
1195/**
1196 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1197 * @hdd_ipa: HDD IPA struct
1198 *
1199 * Dump entire struct hdd_ipa_sys_pipe
1200 *
1201 * Return: none
1202 */
1203static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1204{
1205 int i;
1206
1207 /* IPA SYS Pipes */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001208 hdd_info("==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001209
1210 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1211 struct hdd_ipa_sys_pipe *sys_pipe;
1212 struct ipa_sys_connect_params *ipa_sys_params;
1213
1214 sys_pipe = &hdd_ipa->sys_pipe[i];
1215 ipa_sys_params = &sys_pipe->ipa_sys_params;
1216
Srinivas Girigowda97852372017-03-06 16:52:59 -08001217 hdd_info("sys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001218 "\tconn_hdl: 0x%x\n"
1219 "\tconn_hdl_valid: %d\n"
1220 "\tnat_en: %d\n"
1221 "\thdr_len %d\n"
1222 "\thdr_additional_const_len: %d\n"
1223 "\thdr_ofst_pkt_size_valid: %d\n"
1224 "\thdr_ofst_pkt_size: %d\n"
1225 "\thdr_little_endian: %d\n"
1226 "\tmode: %d\n"
1227 "\tclient: %d\n"
1228 "\tdesc_fifo_sz: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001229 "\tpriv: %pK\n"
1230 "\tnotify: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001231 "\tskip_ep_cfg: %d\n"
1232 "\tkeep_ipa_awake: %d\n",
1233 i,
1234 sys_pipe->conn_hdl,
1235 sys_pipe->conn_hdl_valid,
1236 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1237 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1238 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1239 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1240 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1241 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1242 ipa_sys_params->ipa_ep_cfg.mode.mode,
1243 ipa_sys_params->client,
1244 ipa_sys_params->desc_fifo_sz,
1245 ipa_sys_params->priv,
1246 ipa_sys_params->notify,
1247 ipa_sys_params->skip_ep_cfg,
1248 ipa_sys_params->keep_ipa_awake);
1249 }
1250}
1251
1252/**
1253 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1254 * @hdd_ipa: HDD IPA struct
1255 *
1256 * Dump entire struct hdd_ipa_iface_context
1257 *
1258 * Return: none
1259 */
1260static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1261{
1262 int i;
1263
1264 /* IPA Interface Contexts */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001265 hdd_info("==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001266
1267 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1268 struct hdd_ipa_iface_context *iface_context;
1269
1270 iface_context = &hdd_ipa->iface_context[i];
1271
Srinivas Girigowda97852372017-03-06 16:52:59 -08001272 hdd_info("iface_context[%d]----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001273 "\thdd_ipa: %pK\n"
1274 "\tadapter: %pK\n"
1275 "\ttl_context: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001276 "\tcons_client: %d\n"
1277 "\tprod_client: %d\n"
1278 "\tiface_id: %d\n"
1279 "\tsta_id: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001280 "\tinterface_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001281 "\tifa_address: 0x%x\n",
1282 i,
1283 iface_context->hdd_ipa,
1284 iface_context->adapter,
1285 iface_context->tl_context,
1286 iface_context->cons_client,
1287 iface_context->prod_client,
1288 iface_context->iface_id,
1289 iface_context->sta_id,
1290 &iface_context->interface_lock,
1291 iface_context->ifa_address);
1292 }
1293}
1294
1295/**
1296 * hdd_ipa_dump_info() - dump HDD IPA struct
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001297 * @hdd_ctx: hdd main context
Yun Parkb187d542016-11-14 18:10:04 -08001298 *
1299 * Dump entire struct hdd_ipa
1300 *
1301 * Return: none
1302 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001303void hdd_ipa_dump_info(struct hdd_context *hdd_ctx)
Yun Parkb187d542016-11-14 18:10:04 -08001304{
1305 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1306
1307 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1308 hdd_ipa_dump_sys_pipe(hdd_ipa);
1309 hdd_ipa_dump_iface_context(hdd_ipa);
1310}
1311
1312/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001313 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1314 * enabled
1315 *
1316 * This routine is called to set TX flow info if IPA is enabled
1317 *
1318 * Return: None
1319 */
1320void hdd_ipa_set_tx_flow_info(void)
1321{
1322 hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL;
1323 QDF_STATUS status;
Jeff Johnson49d45e62017-08-29 14:30:42 -07001324 struct hdd_adapter *adapter;
Jeff Johnsond377dce2017-10-04 10:32:42 -07001325 struct hdd_station_ctx *sta_ctx;
Jeff Johnson87251032017-08-29 13:31:11 -07001326 struct hdd_ap_ctx *hdd_ap_ctx;
Jeff Johnsonca2530c2017-09-30 18:25:40 -07001327 struct hdd_hostapd_state *hostapd_state;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001328 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1329 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1330 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1331 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1332 const char *p2pMode = "DEV";
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001333 struct hdd_context *hdd_ctx;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001334 cds_context_type *cds_ctx;
1335#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1336 uint8_t targetChannel = 0;
1337 uint8_t preAdapterChannel = 0;
1338 uint8_t channel24;
1339 uint8_t channel5;
Jeff Johnson49d45e62017-08-29 14:30:42 -07001340 struct hdd_adapter *preAdapterContext = NULL;
1341 struct hdd_adapter *adapter2_4 = NULL;
1342 struct hdd_adapter *adapter5 = NULL;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001343 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1344#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1345 struct wlan_objmgr_psoc *psoc;
1346
1347 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1348 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001349 hdd_err("HDD context is NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001350 return;
1351 }
1352
1353 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1354 if (!cds_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001355 hdd_err("Invalid CDS Context");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001356 return;
1357 }
1358
1359 psoc = hdd_ctx->hdd_psoc;
1360 status = hdd_get_front_adapter(hdd_ctx, &adapterNode);
1361 while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnson57eb2732017-10-02 11:40:20 -07001362 adapter = adapterNode->adapter;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001363 switch (adapter->device_mode) {
1364 case QDF_STA_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001365 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001366 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001367 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001368 staChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001369 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001370 qdf_copy_macaddr(&staBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001371 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001372#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1373 targetChannel = staChannel;
1374#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1375 }
1376 break;
1377 case QDF_P2P_CLIENT_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001378 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001379 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001380 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001381 p2pChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001382 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001383 qdf_copy_macaddr(&p2pBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001384 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001385 p2pMode = "CLI";
1386#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1387 targetChannel = p2pChannel;
1388#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1389 }
1390 break;
1391 case QDF_P2P_GO_MODE:
1392 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1393 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1394 if (hostapd_state->bssState == BSS_START
1395 && hostapd_state->qdf_status ==
1396 QDF_STATUS_SUCCESS) {
1397 p2pChannel = hdd_ap_ctx->operatingChannel;
1398 qdf_copy_macaddr(&p2pBssid,
1399 &adapter->macAddressCurrent);
1400#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1401 targetChannel = p2pChannel;
1402#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1403 }
1404 p2pMode = "GO";
1405 break;
1406 case QDF_SAP_MODE:
1407 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1408 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1409 if (hostapd_state->bssState == BSS_START
1410 && hostapd_state->qdf_status ==
1411 QDF_STATUS_SUCCESS) {
1412 apChannel = hdd_ap_ctx->operatingChannel;
1413 qdf_copy_macaddr(&apBssid,
1414 &adapter->macAddressCurrent);
1415#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1416 targetChannel = apChannel;
1417#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1418 }
1419 break;
1420 case QDF_IBSS_MODE:
1421 default:
1422 break;
1423 }
1424#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1425 if (targetChannel) {
1426 /*
1427 * This is first adapter detected as active
1428 * set as default for none concurrency case
1429 */
1430 if (!preAdapterChannel) {
1431 /* If IPA UC data path is enabled,
1432 * target should reserve extra tx descriptors
1433 * for IPA data path.
1434 * Then host data path should allow less TX
1435 * packet pumping in case IPA
1436 * data path enabled
1437 */
1438 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1439 (QDF_SAP_MODE == adapter->device_mode)) {
1440 adapter->tx_flow_low_watermark =
1441 hdd_ctx->config->TxFlowLowWaterMark +
1442 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1443 } else {
1444 adapter->tx_flow_low_watermark =
1445 hdd_ctx->config->
1446 TxFlowLowWaterMark;
1447 }
1448 adapter->tx_flow_high_watermark_offset =
1449 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1450 cdp_fc_ll_set_tx_pause_q_depth(soc,
1451 adapter->sessionId,
1452 hdd_ctx->config->TxFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001453 hdd_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001454 adapter->device_mode,
1455 targetChannel,
1456 adapter->tx_flow_low_watermark,
1457 adapter->tx_flow_low_watermark +
1458 adapter->tx_flow_high_watermark_offset,
1459 hdd_ctx->config->TxFlowMaxQueueDepth);
1460 preAdapterChannel = targetChannel;
1461 preAdapterContext = adapter;
1462 } else {
1463 /*
1464 * SCC, disable TX flow control for both
1465 * SCC each adapter cannot reserve dedicated
1466 * channel resource, as a result, if any adapter
1467 * blocked OS Q by flow control,
1468 * blocked adapter will lost chance to recover
1469 */
1470 if (preAdapterChannel == targetChannel) {
1471 /* Current adapter */
1472 adapter->tx_flow_low_watermark = 0;
1473 adapter->
1474 tx_flow_high_watermark_offset = 0;
1475 cdp_fc_ll_set_tx_pause_q_depth(soc,
1476 adapter->sessionId,
1477 hdd_ctx->config->
1478 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001479 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001480 hdd_device_mode_to_string(
1481 adapter->device_mode),
1482 adapter->device_mode,
1483 targetChannel,
1484 adapter->tx_flow_low_watermark,
1485 adapter->tx_flow_low_watermark +
1486 adapter->
1487 tx_flow_high_watermark_offset,
1488 hdd_ctx->config->
1489 TxHbwFlowMaxQueueDepth);
1490
1491 if (!preAdapterContext) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001492 hdd_err("SCC: Previous adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001493 continue;
1494 }
1495
1496 /* Previous adapter */
1497 preAdapterContext->
1498 tx_flow_low_watermark = 0;
1499 preAdapterContext->
1500 tx_flow_high_watermark_offset = 0;
1501 cdp_fc_ll_set_tx_pause_q_depth(soc,
1502 preAdapterContext->sessionId,
1503 hdd_ctx->config->
1504 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001505 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001506 hdd_device_mode_to_string(
1507 preAdapterContext->device_mode
1508 ),
1509 preAdapterContext->device_mode,
1510 targetChannel,
1511 preAdapterContext->
1512 tx_flow_low_watermark,
1513 preAdapterContext->
1514 tx_flow_low_watermark +
1515 preAdapterContext->
1516 tx_flow_high_watermark_offset,
1517 hdd_ctx->config->
1518 TxHbwFlowMaxQueueDepth);
1519 }
1520 /*
1521 * MCC, each adapter will have dedicated
1522 * resource
1523 */
1524 else {
1525 /* current channel is 2.4 */
1526 if (targetChannel <=
1527 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1528 channel24 = targetChannel;
1529 channel5 = preAdapterChannel;
1530 adapter2_4 = adapter;
1531 adapter5 = preAdapterContext;
1532 } else {
1533 /* Current channel is 5 */
1534 channel24 = preAdapterChannel;
1535 channel5 = targetChannel;
1536 adapter2_4 = preAdapterContext;
1537 adapter5 = adapter;
1538 }
1539
1540 if (!adapter5) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001541 hdd_err("MCC: 5GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001542 continue;
1543 }
1544 adapter5->tx_flow_low_watermark =
1545 hdd_ctx->config->
1546 TxHbwFlowLowWaterMark;
1547 adapter5->
1548 tx_flow_high_watermark_offset =
1549 hdd_ctx->config->
1550 TxHbwFlowHighWaterMarkOffset;
1551 cdp_fc_ll_set_tx_pause_q_depth(soc,
1552 adapter5->sessionId,
1553 hdd_ctx->config->
1554 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001555 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001556 hdd_device_mode_to_string(
1557 adapter5->device_mode),
1558 adapter5->device_mode,
1559 channel5,
1560 adapter5->tx_flow_low_watermark,
1561 adapter5->
1562 tx_flow_low_watermark +
1563 adapter5->
1564 tx_flow_high_watermark_offset,
1565 hdd_ctx->config->
1566 TxHbwFlowMaxQueueDepth);
1567
1568 if (!adapter2_4) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001569 hdd_err("MCC: 2.4GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001570 continue;
1571 }
1572 adapter2_4->tx_flow_low_watermark =
1573 hdd_ctx->config->
1574 TxLbwFlowLowWaterMark;
1575 adapter2_4->
1576 tx_flow_high_watermark_offset =
1577 hdd_ctx->config->
1578 TxLbwFlowHighWaterMarkOffset;
1579 cdp_fc_ll_set_tx_pause_q_depth(soc,
1580 adapter2_4->sessionId,
1581 hdd_ctx->config->
1582 TxLbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001583 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001584 hdd_device_mode_to_string(
1585 adapter2_4->device_mode),
1586 adapter2_4->device_mode,
1587 channel24,
1588 adapter2_4->
1589 tx_flow_low_watermark,
1590 adapter2_4->
1591 tx_flow_low_watermark +
1592 adapter2_4->
1593 tx_flow_high_watermark_offset,
1594 hdd_ctx->config->
1595 TxLbwFlowMaxQueueDepth);
1596
1597 }
1598 }
1599 }
1600 targetChannel = 0;
1601#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1602 status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext);
1603 adapterNode = pNext;
1604 }
1605 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1606}
1607
1608/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001609 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001610 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001611 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1612 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613 *
1614 * Return: true if IPA is enabled, false otherwise
1615 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001616static void __hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001617 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1618{
1619 struct hdd_ipa_priv *hdd_ipa;
1620
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001621 *ipa_tx_diff = 0;
1622 *ipa_rx_diff = 0;
1623
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001624 if (wlan_hdd_validate_context(hdd_ctx))
1625 return;
1626
1627 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1628
1629 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1630 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001631 return;
1632 }
1633
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301634 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001635 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1636 (false == hdd_ipa->resource_loading)) {
1637 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1638 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001639 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301640 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641}
1642
1643/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001644 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1645 * @hdd_ctx: Global HDD context
1646 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1647 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1648 *
1649 * Return: true if IPA is enabled, false otherwise
1650 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001651void hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001652 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1653{
1654 cds_ssr_protect(__func__);
1655 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1656 cds_ssr_unprotect(__func__);
1657}
1658
1659/**
1660 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001661 * @adapter: network adapter
1662 * @reason: STAT REQ Reason
1663 *
1664 * Return: None
1665 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07001666static void __hdd_ipa_uc_stat_request(struct hdd_adapter *adapter,
1667 uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001669 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670 struct hdd_ipa_priv *hdd_ipa;
1671
Yun Park637d6482016-10-05 10:51:33 -07001672 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001673 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001674
Jeff Johnson399c6272017-08-30 10:51:00 -07001675 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001676
1677 if (wlan_hdd_validate_context(hdd_ctx))
1678 return;
1679
1680 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1681 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1682 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001683 return;
1684 }
1685
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301686 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001687 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1688 (false == hdd_ipa->resource_loading)) {
1689 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07001690 qdf_mutex_release(&hdd_ipa->ipa_lock);
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001691 sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter),
1692 adapter->sessionId,
1693 WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001695 } else {
1696 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698}
1699
1700/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001701 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1702 * @adapter: network adapter
1703 * @reason: STAT REQ Reason
1704 *
1705 * Return: None
1706 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001707void hdd_ipa_uc_stat_request(struct hdd_adapter *adapter, uint8_t reason)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001708{
1709 cds_ssr_protect(__func__);
1710 __hdd_ipa_uc_stat_request(adapter, reason);
1711 cds_ssr_unprotect(__func__);
1712}
1713
Yun Park637d6482016-10-05 10:51:33 -07001714#ifdef FEATURE_METERING
1715/**
1716 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
1717 * @adapter: network adapter
1718 * @reset_stats: reset stat countis after response
1719 *
1720 * Return: None
1721 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001722void hdd_ipa_uc_sharing_stats_request(struct hdd_adapter *adapter,
Yun Park637d6482016-10-05 10:51:33 -07001723 uint8_t reset_stats)
1724{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001725 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001726 struct hdd_ipa_priv *hdd_ipa;
1727
1728 if (!adapter)
1729 return;
1730
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001731 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1732 hdd_ipa = hdd_ctx->hdd_ipa;
1733 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1734 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001735 return;
1736 }
1737
1738 HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats);
1739 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001740 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001741 qdf_mutex_release(&hdd_ipa->ipa_lock);
1742 wma_cli_set_command(
1743 (int)adapter->sessionId,
1744 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
1745 reset_stats, VDEV_CMD);
1746 } else {
1747 qdf_mutex_release(&hdd_ipa->ipa_lock);
1748 }
1749}
1750
1751/**
1752 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
1753 * @adapter: network adapter
1754 * @set_quota: when 1, FW starts quota monitoring
1755 * @quota_bytes: quota limit in bytes
1756 *
1757 * Return: None
1758 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001759void hdd_ipa_uc_set_quota(struct hdd_adapter *adapter, uint8_t set_quota,
Yun Park637d6482016-10-05 10:51:33 -07001760 uint64_t quota_bytes)
1761{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001762 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001763 struct hdd_ipa_priv *hdd_ipa;
1764
1765 if (!adapter)
1766 return;
1767
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001768 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1769 hdd_ipa = hdd_ctx->hdd_ipa;
1770 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1771 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001772 return;
1773 }
1774
1775 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
1776 set_quota, quota_bytes);
1777
1778 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001779 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001780 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park327e7812017-02-14 15:18:10 -08001781 wma_cli_set2_command(
Yun Park637d6482016-10-05 10:51:33 -07001782 (int)adapter->sessionId,
1783 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
Yun Park327e7812017-02-14 15:18:10 -08001784 (set_quota ? quota_bytes&0xffffffff : 0),
1785 (set_quota ? quota_bytes>>32 : 0),
1786 VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001787 } else {
1788 qdf_mutex_release(&hdd_ipa->ipa_lock);
1789 }
1790}
1791#endif
1792
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001793/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1795 * @hdd_ipa: Global HDD IPA context
1796 * @sta_add: Should station be added
1797 * @sta_id: ID of the station being queried
1798 *
1799 * Return: true if the station was found
1800 */
1801static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1802 bool sta_add, uint8_t sta_id)
1803{
1804 bool sta_found = false;
1805 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001806
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1808 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1809 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1810 sta_found = true;
1811 break;
1812 }
1813 }
1814 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301815 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001816 "STA ID %d already exist, cannot add", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817 return sta_found;
1818 }
1819 if (sta_add) {
1820 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1821 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1822 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1823 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1824 return sta_found;
1825 }
1826 }
1827 }
1828 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301829 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001830 "STA ID %d does not exist, cannot delete", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001831 return sta_found;
1832 }
1833 if (!sta_add) {
1834 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1835 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1836 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1837 hdd_ipa->assoc_stas_map[idx].is_reserved =
1838 false;
1839 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1840 return sta_found;
1841 }
1842 }
1843 }
1844 return sta_found;
1845}
1846
1847/**
1848 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1849 * @hdd_ipa: Global HDD IPA context
1850 *
1851 * Return: 0 on success, negative errno if error
1852 */
1853static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1854{
Yun Parkfec73dc2017-09-06 10:40:07 -07001855 int result = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07001856 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07001857 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858
Yun Park199c2ed2017-10-02 11:24:22 -07001859 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
1860
1861 if (!hdd_ipa->ipa_pipes_down) {
1862 /*
1863 * This shouldn't happen :
1864 * IPA WDI Pipes are already activated
1865 */
1866 WARN_ON(1);
1867 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
1868 "IPA WDI Pipes are already activated");
1869 goto end;
1870 }
Yun Parkfec73dc2017-09-06 10:40:07 -07001871
Yun Parkb4f591d2017-03-29 15:51:01 -07001872 result = cdp_ipa_enable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001873 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301874 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001875 "Enable PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001876 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878
Yun Park777d7242017-03-30 15:38:33 -07001879 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Leo Change3e49442015-10-26 20:07:13 -07001880 hdd_ipa->ipa_pipes_down = false;
Yun Parkb4f591d2017-03-29 15:51:01 -07001881
1882 cdp_ipa_enable_autonomy(soc, (struct cdp_pdev *)pdev);
1883
Yun Parkfec73dc2017-09-06 10:40:07 -07001884end:
Yun Park199c2ed2017-10-02 11:24:22 -07001885 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07001886 hdd_ipa->ipa_pipes_down);
Yun Park199c2ed2017-10-02 11:24:22 -07001887
Yun Parkfec73dc2017-09-06 10:40:07 -07001888 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001889}
1890
1891/**
1892 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1893 * @hdd_ipa: Global HDD IPA context
1894 *
1895 * Return: 0 on success, negative errno if error
1896 */
1897static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1898{
Yun Parkb4f591d2017-03-29 15:51:01 -07001899 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1900 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkfec73dc2017-09-06 10:40:07 -07001901 int result = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001902
Yun Park199c2ed2017-10-02 11:24:22 -07001903 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
1904
1905 if (hdd_ipa->ipa_pipes_down) {
1906 /*
1907 * This shouldn't happen :
1908 * IPA WDI Pipes are already deactivated
1909 */
1910 WARN_ON(1);
1911 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
1912 "IPA WDI Pipes are already deactivated");
1913 goto end;
1914 }
Leo Change3e49442015-10-26 20:07:13 -07001915
Yun Parkb4f591d2017-03-29 15:51:01 -07001916 cdp_ipa_disable_autonomy(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001917
Yun Parkb4f591d2017-03-29 15:51:01 -07001918 result = cdp_ipa_disable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001919 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301920 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001921 "Disable WDI PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001922 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001923 }
1924
Yun Parkfec73dc2017-09-06 10:40:07 -07001925 hdd_ipa->ipa_pipes_down = true;
1926
1927end:
Yun Park199c2ed2017-10-02 11:24:22 -07001928 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07001929 hdd_ipa->ipa_pipes_down);
1930 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001931}
1932
1933/**
1934 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1935 * @hdd_ipa: Global HDD IPA context
1936 *
1937 * Return: 0 on success, negative errno if error
1938 */
1939static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1940{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001941 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07001942
Yun Park199c2ed2017-10-02 11:24:22 -07001943 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07001944
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945 hdd_ipa->activated_fw_pipe = 0;
1946 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001947
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948 /* If RM feature enabled
1949 * Request PROD Resource first
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07001950 * PROD resource may return sync or async manners
1951 */
Yun Parkb4f591d2017-03-29 15:51:01 -07001952 if (hdd_ipa_is_rm_enabled(hdd_ctx)) {
Yun Park4cab6ee2015-10-27 11:43:40 -07001953 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1954 /* RM PROD request sync return
1955 * enable pipe immediately
1956 */
1957 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301958 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001959 "IPA WDI Pipe activation failed");
Yun Park4cab6ee2015-10-27 11:43:40 -07001960 hdd_ipa->resource_loading = false;
1961 return -EBUSY;
1962 }
Sravan Kumar Kairamc76f28a2017-07-25 19:03:40 +05301963 } else {
1964 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park199c2ed2017-10-02 11:24:22 -07001965 "IPA WDI Pipe activation deferred");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001966 }
1967 } else {
1968 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001969 * Just enabled all the PIPEs
1970 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001971 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301972 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001973 "IPA WDI Pipe activation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 hdd_ipa->resource_loading = false;
1975 return -EBUSY;
1976 }
1977 hdd_ipa->resource_loading = false;
1978 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001979
Yun Park199c2ed2017-10-02 11:24:22 -07001980 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001981 return 0;
1982}
1983
1984/**
1985 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1986 * @hdd_ipa: Global HDD IPA context
1987 *
1988 * Return: None
1989 */
1990static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1991{
Leo Changfdb45c32016-10-28 11:09:23 -07001992 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07001993 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001994
Yun Park199c2ed2017-10-02 11:24:22 -07001995 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07001996
Yun Parkb4f591d2017-03-29 15:51:01 -07001997 if (!pdev) {
Yun Park7c4f31b2016-11-30 10:09:21 -08001998 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
1999 QDF_ASSERT(0);
2000 return;
2001 }
2002
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003 hdd_ipa->resource_unloading = true;
Yun Park777d7242017-03-30 15:38:33 -07002004 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Yun Parkb4f591d2017-03-29 15:51:01 -07002005 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW RX PIPE");
2006 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, false);
2007 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW TX PIPE");
2008 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, true);
Yun Parkfec73dc2017-09-06 10:40:07 -07002009
Yun Park199c2ed2017-10-02 11:24:22 -07002010 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: IPA WDI Pipes deactivated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011}
2012
2013/**
2014 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2015 * @context: User context registered with TL (the IPA Global context is
2016 * registered
2017 * @rxpkt: Packet containing the notification
2018 * @staid: ID of the station associated with the packet
2019 *
2020 * Return: None
2021 */
2022static void
2023hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
2024{
2025 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302026 QDF_STATUS status = QDF_STATUS_SUCCESS;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002027 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002028
2029 /*
2030 * When SSR is going on or driver is unloading, just return.
2031 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002032 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302033 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002034 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002035
Yun Parkb4f591d2017-03-29 15:51:01 -07002036 if (!hdd_ipa_is_rm_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037 return;
2038
Srinivas Girigowda97852372017-03-06 16:52:59 -08002039 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002040 __func__, event);
2041
2042 switch (event) {
2043 case IPA_RM_RESOURCE_GRANTED:
2044 /* Differed RM Granted */
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302045 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046 if ((false == hdd_ipa->resource_unloading) &&
2047 (!hdd_ipa->activated_fw_pipe)) {
2048 hdd_ipa_uc_enable_pipes(hdd_ipa);
2049 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302050 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051 break;
2052
2053 case IPA_RM_RESOURCE_RELEASED:
2054 /* Differed RM Released */
2055 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002056 break;
2057
2058 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302059 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002060 "%s, invalid event code %d", __func__, event);
2061 break;
2062 }
2063}
2064
2065/**
2066 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2067 * @hdd_ipa: Global HDD IPA context
2068 * @event: IPA resource manager event to be deferred
2069 *
2070 * This function is called when a resource manager event is received
2071 * from firmware in interrupt context. This function will defer the
2072 * handling to the OL RX thread
2073 *
2074 * Return: None
2075 */
2076static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2077{
2078 enum ipa_rm_event event;
2079 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2080 struct uc_rm_work_struct, work);
2081 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2082 struct hdd_ipa_priv, uc_rm_work);
2083
2084 cds_ssr_protect(__func__);
2085 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002086 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087 "%s, posted event %d", __func__, event);
2088
2089 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2090 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002091}
2092
2093/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002094 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
Yun Parkb4f591d2017-03-29 15:51:01 -07002095 * @hdd_ipa: hdd ipa local context
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002096 *
2097 * Will handle IPA UC image loaded indication comes from IPA kernel
2098 *
2099 * Return: None
2100 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002101static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *hdd_ipa)
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002102{
Yun Parkb4f591d2017-03-29 15:51:01 -07002103 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2104 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002105 struct hdd_context *hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07002106 QDF_STATUS status;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002107
2108 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
Yun Parkb4f591d2017-03-29 15:51:01 -07002109 if (true == hdd_ipa->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002110 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002111 __func__);
2112 return;
2113 }
2114
Yun Parkb4f591d2017-03-29 15:51:01 -07002115 hdd_ctx = hdd_ipa->hdd_ctx;
2116 hdd_ipa->uc_loaded = true;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002117
Yun Parkb4f591d2017-03-29 15:51:01 -07002118 /* Connect pipe */
2119 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
2120 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
2121 hdd_ipa_wdi_meter_notifier_cb,
2122 hdd_ctx->config->IpaDescSize,
2123 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
2124 &hdd_ipa->tx_pipe_handle,
2125 &hdd_ipa->rx_pipe_handle);
2126 if (status) {
2127 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2128 "Failure to setup IPA pipes (status=%d)",
2129 status);
2130 return;
2131 }
2132
2133 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002134
2135 /* If already any STA connected, enable IPA/FW PIPEs */
Yun Parkb4f591d2017-03-29 15:51:01 -07002136 if (hdd_ipa->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002137 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002138 "Client already connected, enable IPA/FW PIPEs");
Yun Parkb4f591d2017-03-29 15:51:01 -07002139 hdd_ipa_uc_handle_first_con(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002140 }
2141}
2142
2143/**
Yun Park637d6482016-10-05 10:51:33 -07002144 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2145 * @hdd_ctx: Global HDD context
2146 * @op_msg: operation message received from firmware
2147 *
2148 * Return: QDF_STATUS enumeration
2149 */
2150#ifdef FEATURE_METERING
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002151static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002152 struct op_msg_type *op_msg)
2153{
2154 struct op_msg_type *msg = op_msg;
2155 struct ipa_uc_sharing_stats *uc_sharing_stats;
2156 struct ipa_uc_quota_rsp *uc_quota_rsp;
2157 struct ipa_uc_quota_ind *uc_quota_ind;
2158 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002159 struct hdd_adapter *adapter;
Yun Park637d6482016-10-05 10:51:33 -07002160
2161 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2162
2163 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2164 /* fill-up ipa_uc_sharing_stats structure from FW */
2165 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2166 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2167
2168 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2169 sizeof(struct ipa_uc_sharing_stats));
2170
2171 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2172
2173 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2174 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2175 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2176 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2177 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2178 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2179 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2180 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2181 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2182 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2183 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2184 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2185 /* received set quota response */
2186 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2187 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2188
2189 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2190 sizeof(struct ipa_uc_quota_rsp));
2191
2192 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2193 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2194 "%s: success=%d, quota_bytes=%llu",
2195 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2196 hdd_ipa->ipa_quota_rsp.success,
2197 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2198 hdd_ipa->ipa_quota_rsp.quota_lo);
2199 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2200 /* hit quota limit */
2201 uc_quota_ind = (struct ipa_uc_quota_ind *)
2202 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2203
2204 hdd_ipa->ipa_quota_ind.quota_bytes =
2205 uc_quota_ind->quota_bytes;
2206
2207 /* send quota exceeded indication to IPA */
2208 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2209 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2210 hdd_ipa->ipa_quota_ind.quota_bytes);
2211
2212 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2213 if (adapter)
2214 ipa_broadcast_wdi_quota_reach_ind(
2215 adapter->dev->ifindex,
2216 uc_quota_ind->quota_bytes);
2217 else
2218 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2219 "Failed quota_reach_ind: NULL adapter");
2220 } else {
2221 return QDF_STATUS_E_INVAL;
2222 }
2223
2224 return QDF_STATUS_SUCCESS;
2225}
2226#else
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002227static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002228 struct op_msg_type *op_msg)
2229{
2230 return QDF_STATUS_E_INVAL;
2231}
2232#endif
2233
Yun Park657c7d72017-06-07 15:44:59 -07002234#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0))
2235/* older versions had a typo */
2236#define num_bam_int_in_non_running_state num_bam_int_in_non_runnning_state
2237#endif
2238
Yun Park637d6482016-10-05 10:51:33 -07002239/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002240 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2241 * @op_msg: operation message received from firmware
2242 * @usr_ctxt: user context registered with TL (we register the HDD Global
2243 * context)
2244 *
2245 * Return: None
2246 */
2247static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2248{
2249 struct op_msg_type *msg = op_msg;
2250 struct ipa_uc_fw_stats *uc_fw_stat;
2251 struct IpaHwStatsWDIInfoData_t ipa_stat;
2252 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002253 struct hdd_context *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302254 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002255
2256 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302257 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002258 return;
2259 }
2260
2261 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302262 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002263 "%s, INVALID OPCODE %d", __func__, msg->op_code);
jiadd91a6842017-08-01 14:46:02 +08002264 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002265 return;
2266 }
2267
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002268 hdd_ctx = (struct hdd_context *) usr_ctxt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002269
2270 /*
2271 * When SSR is going on or driver is unloading, just return.
2272 */
2273 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302274 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302275 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002276 return;
2277 }
2278
2279 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2280
Govind Singhb6a89772016-08-12 11:23:35 +05302281 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002282 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002283
2284 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2285 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302286 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002287 hdd_ipa->activated_fw_pipe++;
2288 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2289 hdd_ipa->resource_loading = false;
Yun Park777d7242017-03-30 15:38:33 -07002290 complete(&hdd_ipa->ipa_resource_comp);
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002291 if (hdd_ipa->wdi_enabled == false) {
2292 hdd_ipa->wdi_enabled = true;
2293 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2294 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2295 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002296 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002297 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002298 if (hdd_ipa->pending_cons_req)
2299 ipa_rm_notify_completion(
2300 IPA_RM_RESOURCE_GRANTED,
2301 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002302 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002303 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302304 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002305 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002306 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302307 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002308 hdd_ipa->activated_fw_pipe--;
2309 if (!hdd_ipa->activated_fw_pipe) {
Yun Park777d7242017-03-30 15:38:33 -07002310 /*
2311 * Async return success from FW
2312 * Disable/suspend all the PIPEs
2313 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002314 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002315 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2316 ipa_rm_release_resource(
2317 IPA_RM_RESOURCE_WLAN_PROD);
Yun Park5b635012015-12-02 15:05:01 -08002318 hdd_ipa->resource_unloading = false;
Yun Park777d7242017-03-30 15:38:33 -07002319 complete(&hdd_ipa->ipa_resource_comp);
Yun Park5b635012015-12-02 15:05:01 -08002320 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2321 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002322 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302323 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002324 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002325 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002326 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302327 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002328 "==== IPA_UC WLAN_HOST RX ====\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08002330 "NUM TX FWD OK : %llu\n"
2331 "NUM TX FWD ERR : %llu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002332 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08002333 hdd_ipa->stats.num_tx_fwd_ok,
2334 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302335 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002336 "==== IPA_UC WLAN_HOST CONTROL ====\n"
2337 "SAP NUM STAs: %d\n"
2338 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08002339 "CONCURRENT MODE: %s\n"
2340 "TX PIPE HDL: 0x%x\n"
2341 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002342 "RSC LOADING : %d\n"
2343 "RSC UNLOADING : %d\n"
2344 "PNDNG CNS RQT : %d",
2345 hdd_ipa->sap_num_connected_sta,
2346 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08002347 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002348 hdd_ipa->tx_pipe_handle,
2349 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08002350 hdd_ipa->resource_loading,
2351 hdd_ipa->resource_unloading,
2352 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002353
2354 /* STATs from FW */
2355 uc_fw_stat = (struct ipa_uc_fw_stats *)
2356 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302357 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002358 "==== IPA_UC WLAN_FW TX ====\n"
2359 "COMP RING BASE: 0x%x\n"
2360 "COMP RING SIZE: %d\n"
2361 "COMP RING DBELL : 0x%x\n"
2362 "COMP RING DBELL IND VAL : %d\n"
2363 "COMP RING DBELL CACHED VAL : %d\n"
2364 "COMP RING DBELL CACHED VAL : %d\n"
2365 "PKTS ENQ : %d\n"
2366 "PKTS COMP : %d\n"
2367 "IS SUSPEND : %d\n"
2368 "RSVD : 0x%x",
2369 uc_fw_stat->tx_comp_ring_base,
2370 uc_fw_stat->tx_comp_ring_size,
2371 uc_fw_stat->tx_comp_ring_dbell_addr,
2372 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2373 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2374 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2375 uc_fw_stat->tx_pkts_enqueued,
2376 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002377 uc_fw_stat->tx_is_suspend,
2378 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302379 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002380 "==== IPA_UC WLAN_FW RX ====\n"
2381 "IND RING BASE: 0x%x\n"
2382 "IND RING SIZE: %d\n"
2383 "IND RING DBELL : 0x%x\n"
2384 "IND RING DBELL IND VAL : %d\n"
2385 "IND RING DBELL CACHED VAL : %d\n"
2386 "RDY IND ADDR : 0x%x\n"
2387 "RDY IND CACHE VAL : %d\n"
2388 "RFIL IND : %d\n"
2389 "NUM PKT INDICAT : %d\n"
2390 "BUF REFIL : %d\n"
2391 "NUM DROP NO SPC : %d\n"
2392 "NUM DROP NO BUF : %d\n"
2393 "IS SUSPND : %d\n"
2394 "RSVD : 0x%x\n",
2395 uc_fw_stat->rx_ind_ring_base,
2396 uc_fw_stat->rx_ind_ring_size,
2397 uc_fw_stat->rx_ind_ring_dbell_addr,
2398 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2399 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2400 uc_fw_stat->rx_ind_ring_rdidx_addr,
2401 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2402 uc_fw_stat->rx_refill_idx,
2403 uc_fw_stat->rx_num_pkts_indicated,
2404 uc_fw_stat->rx_buf_refilled,
2405 uc_fw_stat->rx_num_ind_drop_no_space,
2406 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002407 uc_fw_stat->rx_is_suspend,
2408 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002409 /* STATs from IPA */
2410 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302411 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002412 "==== IPA_UC IPA TX ====\n"
2413 "NUM PROCD : %d\n"
2414 "CE DBELL : 0x%x\n"
2415 "NUM DBELL FIRED : %d\n"
2416 "COMP RNG FULL : %d\n"
2417 "COMP RNG EMPT : %d\n"
2418 "COMP RNG USE HGH : %d\n"
2419 "COMP RNG USE LOW : %d\n"
2420 "BAM FIFO FULL : %d\n"
2421 "BAM FIFO EMPT : %d\n"
2422 "BAM FIFO USE HGH : %d\n"
2423 "BAM FIFO USE LOW : %d\n"
2424 "NUM DBELL : %d\n"
2425 "NUM UNEXP DBELL : %d\n"
2426 "NUM BAM INT HDL : 0x%x\n"
2427 "NUM BAM INT NON-RUN : 0x%x\n"
2428 "NUM QMB INT HDL : 0x%x",
2429 ipa_stat.tx_ch_stats.num_pkts_processed,
2430 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2431 ipa_stat.tx_ch_stats.num_db_fired,
2432 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2433 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2434 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2435 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2436 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2437 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2438 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2439 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2440 ipa_stat.tx_ch_stats.num_db,
2441 ipa_stat.tx_ch_stats.num_unexpected_db,
2442 ipa_stat.tx_ch_stats.num_bam_int_handled,
2443 ipa_stat.tx_ch_stats.
Yun Park657c7d72017-06-07 15:44:59 -07002444 num_bam_int_in_non_running_state,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002445 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2446
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302447 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002448 "==== IPA_UC IPA RX ====\n"
2449 "MAX OST PKT : %d\n"
2450 "NUM PKT PRCSD : %d\n"
2451 "RNG RP : 0x%x\n"
2452 "COMP RNG FULL : %d\n"
2453 "COMP RNG EMPT : %d\n"
2454 "COMP RNG USE HGH : %d\n"
2455 "COMP RNG USE LOW : %d\n"
2456 "BAM FIFO FULL : %d\n"
2457 "BAM FIFO EMPT : %d\n"
2458 "BAM FIFO USE HGH : %d\n"
2459 "BAM FIFO USE LOW : %d\n"
2460 "NUM DB : %d\n"
2461 "NUM UNEXP DB : %d\n"
2462 "NUM BAM INT HNDL : 0x%x\n",
2463 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2464 ipa_stat.rx_ch_stats.num_pkts_processed,
2465 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2466 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2467 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2468 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2469 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2470 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2471 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2472 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2473 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2474 ipa_stat.rx_ch_stats.num_db,
2475 ipa_stat.rx_ch_stats.num_unexpected_db,
2476 ipa_stat.rx_ch_stats.num_bam_int_handled);
2477 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2478 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2479 /* STATs from FW */
2480 uc_fw_stat = (struct ipa_uc_fw_stats *)
2481 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302482 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002483 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2484 uc_fw_stat->tx_pkts_completed,
2485 hdd_ipa->ipa_p_tx_packets);
2486 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2487 (uc_fw_stat->rx_num_ind_drop_no_space +
2488 uc_fw_stat->rx_num_ind_drop_no_buf +
2489 uc_fw_stat->rx_num_pkts_indicated),
2490 hdd_ipa->ipa_p_rx_packets);
2491
2492 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2493 hdd_ipa->ipa_p_rx_packets =
2494 (uc_fw_stat->rx_num_ind_drop_no_space +
2495 uc_fw_stat->rx_num_ind_drop_no_buf +
2496 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302497 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002498 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2499 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2500 hdd_ipa_uc_loaded_handler(hdd_ipa);
2501 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002502 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2503 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2504 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002505 }
Yun Park8957d802017-01-25 12:27:29 -08002506
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302507 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002508}
2509
2510
2511/**
2512 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2513 * @adapter: device adapter instance
2514 * @offload_type: MCC or SCC
2515 * @enable: TX offload enable or disable
2516 *
2517 * Return: none
2518 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07002519static void hdd_ipa_uc_offload_enable_disable(struct hdd_adapter *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002520 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002521{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002522 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002523 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002524 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002525 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002526
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002527 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002528 return;
2529
Yun Park8292dcb2016-10-07 16:46:06 -07002530 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002531 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002532
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002533 if (!iface_context) {
2534 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2535 "Interface context is NULL");
2536 return;
2537 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08002538 if (session_id >= CSR_ROAM_SESSION_MAX) {
2539 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2540 "invalid session id: %d", session_id);
2541 return;
2542 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002543 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park199c2ed2017-10-02 11:24:22 -07002544 /*
2545 * This shouldn't happen :
2546 * IPA offload status is already set as desired
2547 */
2548 WARN_ON(1);
2549 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
Yun Parkb4f591d2017-03-29 15:51:01 -07002550 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002551 "IPA offload status is already set",
2552 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002553 return;
2554 }
2555
Yun Park4540e862016-11-10 16:30:06 -08002556 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2557 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2558 "invalid session id: %d, offload_type=%d, enable=%d",
2559 adapter->sessionId, offload_type, enable);
2560 return;
2561 }
2562
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302563 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002564 sizeof(ipa_offload_enable_disable));
2565 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002566 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002567 ipa_offload_enable_disable.enable = enable;
2568
Yun Park199c2ed2017-10-02 11:24:22 -07002569 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07002570 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002571 ipa_offload_enable_disable.offload_type,
2572 ipa_offload_enable_disable.vdev_id,
2573 ipa_offload_enable_disable.enable);
2574
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302575 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002576 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2577 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302578 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002579 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
2580 "Failure to enable IPA offload",
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002581 ipa_offload_enable_disable.offload_type,
2582 ipa_offload_enable_disable.vdev_id,
2583 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002584 } else {
2585 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002586 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002587 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002588 }
2589}
2590
2591/**
2592 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2593 * @work: uC OP work
2594 *
2595 * Return: None
2596 */
2597static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2598{
2599 struct op_msg_type *msg;
2600 struct uc_op_work_struct *uc_op_work = container_of(work,
2601 struct uc_op_work_struct, work);
2602 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2603
2604 cds_ssr_protect(__func__);
2605
2606 msg = uc_op_work->msg;
2607 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002608 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002609 "%s, posted msg %d", __func__, msg->op_code);
2610
2611 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2612
2613 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002614}
2615
2616/**
2617 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2618 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2619 * @op_msg: operation message received from firmware
2620 * @hdd_ctx: Global HDD context
2621 *
2622 * Return: None
2623 */
2624static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2625{
2626 struct hdd_ipa_priv *hdd_ipa;
2627 struct op_msg_type *msg;
2628 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302629 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002630
2631 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302632 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002633 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002634
2635 msg = (struct op_msg_type *)op_msg;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002636 hdd_ipa = ((struct hdd_context *)hdd_ctx)->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637
2638 if (unlikely(!hdd_ipa))
2639 goto end;
2640
2641 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Yun Parkb4f591d2017-03-29 15:51:01 -07002642 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid OP Code (%d)",
2643 msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002644 goto end;
2645 }
2646
2647 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2648 if (uc_op_work->msg)
2649 /* When the same uC OPCODE is already pended, just return */
2650 goto end;
2651
2652 uc_op_work->msg = msg;
2653 schedule_work(&uc_op_work->work);
2654 return;
2655
2656end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302657 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002658}
2659
2660/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002661 * hdd_ipa_init_uc_op_work - init ipa uc op work
2662 * @work: struct work_struct
2663 * @work_handler: work_handler
2664 *
2665 * Return: none
2666 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002667static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002668 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002669{
2670 INIT_WORK(work, work_handler);
2671}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002672
Yun Park637d6482016-10-05 10:51:33 -07002673#ifdef FEATURE_METERING
2674/**
2675 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2676 * IPA calls to get WLAN stats or set quota limit.
2677 * @priv: pointer to private data registered with IPA (we register a
2678 *» pointer to the global IPA context)
2679 * @evt: the IPA event which triggered the callback
2680 * @data: data associated with the event
2681 *
2682 * Return: None
2683 */
2684static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2685 void *data)
2686{
2687 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002688 struct hdd_adapter *adapter = NULL;
Yun Park637d6482016-10-05 10:51:33 -07002689 struct ipa_get_wdi_sap_stats *wdi_sap_stats;
2690 struct ipa_set_wifi_quota *ipa_set_quota;
2691 int ret = 0;
2692
2693 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2694 return;
2695
2696 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2697
2698 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2699
2700 switch (evt) {
2701 case IPA_GET_WDI_SAP_STATS:
2702 /* fill-up ipa_get_wdi_sap_stats structure after getting
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07002703 * ipa_uc_fw_stats from FW
2704 */
Yun Park637d6482016-10-05 10:51:33 -07002705 wdi_sap_stats = data;
2706
2707 if (!adapter) {
2708 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2709 "IPA uC share stats failed - no adapter");
2710 wdi_sap_stats->stats_valid = 0;
2711 return;
2712 }
2713
2714 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
Yun Park637d6482016-10-05 10:51:33 -07002715 hdd_ipa_uc_sharing_stats_request(adapter,
2716 wdi_sap_stats->reset_stats);
2717 ret = wait_for_completion_timeout(
2718 &hdd_ipa->ipa_uc_sharing_stats_comp,
2719 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2720 if (!ret) {
2721 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2722 "IPA uC share stats request timed out");
2723 wdi_sap_stats->stats_valid = 0;
2724 } else {
2725 wdi_sap_stats->stats_valid = 1;
2726
2727 wdi_sap_stats->ipv4_rx_packets =
2728 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2729 wdi_sap_stats->ipv4_rx_bytes =
2730 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2731 wdi_sap_stats->ipv6_rx_packets =
2732 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2733 wdi_sap_stats->ipv6_rx_bytes =
2734 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
2735 wdi_sap_stats->ipv4_tx_packets =
2736 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
2737 wdi_sap_stats->ipv4_tx_bytes =
2738 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
2739 wdi_sap_stats->ipv6_tx_packets =
2740 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
2741 wdi_sap_stats->ipv6_tx_bytes =
2742 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
2743 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2744 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2745 "IPA_GET_WDI_SAP_STATS",
2746 wdi_sap_stats->stats_valid,
2747 wdi_sap_stats->ipv4_rx_packets,
2748 wdi_sap_stats->ipv4_rx_bytes,
2749 wdi_sap_stats->ipv6_rx_packets,
2750 wdi_sap_stats->ipv6_rx_bytes,
2751 wdi_sap_stats->ipv4_tx_packets,
2752 wdi_sap_stats->ipv4_tx_bytes,
2753 wdi_sap_stats->ipv6_tx_packets,
2754 wdi_sap_stats->ipv6_tx_bytes);
2755 }
2756 break;
2757 case IPA_SET_WIFI_QUOTA:
2758 /* get ipa_set_wifi_quota structure from IPA and pass to FW
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07002759 * through quota_exceeded field in ipa_uc_fw_stats
2760 */
Yun Park637d6482016-10-05 10:51:33 -07002761 ipa_set_quota = data;
2762
2763 if (!adapter) {
2764 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2765 "IPA uC set quota failed - no adapter");
2766 ipa_set_quota->set_valid = 0;
2767 return;
2768 }
2769
Yun Park777d7242017-03-30 15:38:33 -07002770 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
Yun Park637d6482016-10-05 10:51:33 -07002771 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
2772 ipa_set_quota->quota_bytes);
2773
2774 ret = wait_for_completion_timeout(
2775 &hdd_ipa->ipa_uc_set_quota_comp,
2776 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
2777 if (!ret) {
2778 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2779 "IPA uC set quota request timed out");
2780 ipa_set_quota->set_valid = 0;
2781 } else {
2782 ipa_set_quota->quota_bytes =
2783 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
2784 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
2785 ipa_set_quota->set_valid =
2786 hdd_ipa->ipa_quota_rsp.success;
2787 }
2788
2789 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
2790 ipa_set_quota->quota_bytes,
2791 ipa_set_quota->set_valid);
2792 break;
2793 }
2794}
2795
2796/**
2797 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2798 * IPA calls to get WLAN stats or set quota limit.
2799 * @priv: pointer to private data registered with IPA (we register a
Yun Parkb4f591d2017-03-29 15:51:01 -07002800 * pointer to the global IPA context)
Yun Park637d6482016-10-05 10:51:33 -07002801 * @evt: the IPA event which triggered the callback
2802 * @data: data associated with the event
2803 *
2804 * Return: None
2805 */
2806static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2807 void *data)
2808{
2809 cds_ssr_protect(__func__);
2810 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
2811 cds_ssr_unprotect(__func__);
2812}
2813
Yun Parkb4f591d2017-03-29 15:51:01 -07002814static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07002815{
Yun Park637d6482016-10-05 10:51:33 -07002816 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
2817 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
2818}
2819#else
Yun Parkb4f591d2017-03-29 15:51:01 -07002820static void hdd_ipa_wdi_meter_notifier_cb(void)
2821{
2822}
2823
2824static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07002825{
2826}
2827#endif
2828
Rajeev Kumar217f2172016-01-06 18:11:55 -08002829/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002830 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2831 * @hdd_ctx: Global HDD context
2832 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002833 * This function is called to update IPA pipe configuration with resources
2834 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
2835 * (cds_enable)
2836 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302837 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002838 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002839QDF_STATUS hdd_ipa_uc_ol_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002840{
Yun Parkb4f591d2017-03-29 15:51:01 -07002841 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07002842 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002843 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkb4f591d2017-03-29 15:51:01 -07002844 uint8_t i;
2845 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002846
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002847 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2848 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002849
Yun Park199c2ed2017-10-02 11:24:22 -07002850 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07002851
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002852 /* Do only IPA Pipe specific configuration here. All one time
2853 * initialization wrt IPA UC shall in hdd_ipa_init and those need
2854 * to be reinit at SSR shall in be SSR deinit / reinit functions.
2855 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002856 if (!pdev || !soc) {
2857 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkb4f591d2017-03-29 15:51:01 -07002858 status = QDF_STATUS_E_FAILURE;
Yun Parkbaa62862017-01-18 13:43:34 -08002859 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002860 }
Yun Parkb4f591d2017-03-29 15:51:01 -07002861 if (cdp_ipa_get_resource(soc, (struct cdp_pdev *)pdev)) {
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002862 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2863 "IPA UC resource alloc fail");
Yun Park199c2ed2017-10-02 11:24:22 -07002864 status = QDF_STATUS_E_FAILURE;
2865 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002866 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002867
Yun Parkb4f591d2017-03-29 15:51:01 -07002868 if (true == hdd_ipa->uc_loaded) {
2869 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
2870 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
2871 hdd_ipa_wdi_meter_notifier_cb,
2872 hdd_ctx->config->IpaDescSize,
2873 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
2874 &hdd_ipa->tx_pipe_handle,
2875 &hdd_ipa->rx_pipe_handle);
2876 if (status) {
Yun Parkbaa62862017-01-18 13:43:34 -08002877 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002878 "Failure to setup IPA pipes (status=%d)",
2879 status);
Yun Park199c2ed2017-10-02 11:24:22 -07002880 status = QDF_STATUS_E_FAILURE;
2881 goto fail_return;
Yun Parkbaa62862017-01-18 13:43:34 -08002882 }
Yun Park637d6482016-10-05 10:51:33 -07002883
Yun Parkb4f591d2017-03-29 15:51:01 -07002884 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
2885 hdd_ipa_init_metering(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002886 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002887
Yun Parkb4f591d2017-03-29 15:51:01 -07002888 cdp_ipa_register_op_cb(soc, (struct cdp_pdev *)pdev,
Yun Parkbaa62862017-01-18 13:43:34 -08002889 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
2890
Yun Parkb4f591d2017-03-29 15:51:01 -07002891 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
2892 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
2893 hdd_ipa_uc_fw_op_event_handler);
2894 hdd_ipa->uc_op_work[i].msg = NULL;
2895 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002896
Yun Parkbaa62862017-01-18 13:43:34 -08002897fail_return:
Yun Park199c2ed2017-10-02 11:24:22 -07002898 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: status=%d", status);
Yun Parkb4f591d2017-03-29 15:51:01 -07002899 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002900}
2901
Leo Change3e49442015-10-26 20:07:13 -07002902/**
Yun Parkd8fb1a82017-10-13 16:48:20 -07002903 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
2904 * @hdd_ipa: pointer to HDD IPA struct
2905 *
2906 * Return: none
2907 */
2908static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
2909{
2910 struct ipa_uc_pending_event *pending_event = NULL;
2911
2912 while (qdf_list_remove_front(&hdd_ipa->pending_event,
2913 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
2914 qdf_mem_free(pending_event);
2915}
2916
2917/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302918 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
2919 * @hdd_ctx: Global HDD context
2920 *
2921 * Return: 0 on success, negativer errno on error
2922 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002923int hdd_ipa_uc_ol_deinit(struct hdd_context *hdd_ctx)
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302924{
2925 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
2926 int ret = 0;
Yun Parkb4f591d2017-03-29 15:51:01 -07002927 QDF_STATUS status;
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302928
Yun Park199c2ed2017-10-02 11:24:22 -07002929 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07002930
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302931 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2932 return ret;
2933
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05302934 if (!hdd_ipa->ipa_pipes_down)
2935 hdd_ipa_uc_disable_pipes(hdd_ipa);
2936
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302937 if (true == hdd_ipa->uc_loaded) {
Yun Parkb4f591d2017-03-29 15:51:01 -07002938 status = cdp_ipa_cleanup(cds_get_context(QDF_MODULE_ID_SOC),
2939 hdd_ipa->tx_pipe_handle,
2940 hdd_ipa->rx_pipe_handle);
2941 if (status) {
2942 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2943 "Failure to cleanup IPA pipes (status=%d)",
2944 status);
2945 return -EFAULT;
2946 }
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302947 }
2948
Yun Parkd8fb1a82017-10-13 16:48:20 -07002949 hdd_ipa_cleanup_pending_event(hdd_ipa);
2950
Yun Park199c2ed2017-10-02 11:24:22 -07002951 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: ret=%d", ret);
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302952 return ret;
2953}
2954
2955/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002956 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002957 * @hdd_ctx: hdd main context
2958 *
2959 * Force shutdown IPA pipe
2960 * Independent of FW pipe status, IPA pipe shutdonw progress
2961 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2962 * independent from FW pipe status
2963 *
2964 * Return: NONE
2965 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002966static void __hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002967{
2968 struct hdd_ipa_priv *hdd_ipa;
2969
Yun Park199c2ed2017-10-02 11:24:22 -07002970 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07002971
Leo Change3e49442015-10-26 20:07:13 -07002972 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2973 return;
2974
2975 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2976 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302977 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002978 "IPA pipes are not down yet, force shutdown");
Leo Change3e49442015-10-26 20:07:13 -07002979 hdd_ipa_uc_disable_pipes(hdd_ipa);
2980 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002981 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb4f591d2017-03-29 15:51:01 -07002982 "IPA pipes are down, do nothing");
Leo Change3e49442015-10-26 20:07:13 -07002983 }
Yun Parkfec73dc2017-09-06 10:40:07 -07002984
Yun Park199c2ed2017-10-02 11:24:22 -07002985 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
Leo Change3e49442015-10-26 20:07:13 -07002986}
2987
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002988/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002989 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2990 * __hdd_ipa_uc_force_pipe_shutdown
2991 * @hdd_ctx: hdd main context
2992 *
2993 * Force shutdown IPA pipe
2994 * Independent of FW pipe status, IPA pipe shutdonw progress
2995 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2996 * independent from FW pipe status
2997 *
2998 * Return: NONE
2999 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003000void hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003001{
3002 cds_ssr_protect(__func__);
3003 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
3004 cds_ssr_unprotect(__func__);
3005}
3006
3007/**
Govind Singh9c58eba2016-09-02 16:23:06 +05303008 * hdd_ipa_msg_free_fn() - Free an IPA message
3009 * @buff: pointer to the IPA message
3010 * @len: length of the IPA message
3011 * @type: type of IPA message
3012 *
3013 * Return: None
3014 */
3015static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
3016{
Srinivas Girigowda97852372017-03-06 16:52:59 -08003017 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05303018 ghdd_ipa->stats.num_free_msg++;
3019 qdf_mem_free(buff);
3020}
3021
Govind Singh9c58eba2016-09-02 16:23:06 +05303022/**
jge62037862016-12-09 10:44:33 +08003023 * hdd_ipa_uc_send_evt() - send event to ipa
3024 * @hdd_ctx: pointer to hdd context
3025 * @type: event type
3026 * @mac_addr: pointer to mac address
3027 *
3028 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303029 *
3030 * Return: 0 - Success
3031 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003032static int hdd_ipa_uc_send_evt(struct hdd_adapter *adapter,
jge62037862016-12-09 10:44:33 +08003033 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303034{
jge62037862016-12-09 10:44:33 +08003035 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05303036 struct ipa_msg_meta meta;
3037 struct ipa_wlan_msg *msg;
3038 int ret = 0;
jge62037862016-12-09 10:44:33 +08003039
3040 meta.msg_len = sizeof(struct ipa_wlan_msg);
3041 msg = qdf_mem_malloc(meta.msg_len);
3042 if (msg == NULL) {
3043 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3044 "msg allocation failed");
3045 return -ENOMEM;
3046 }
3047
3048 meta.msg_type = type;
3049 strlcpy(msg->name, adapter->dev->name,
3050 IPA_RESOURCE_NAME_MAX);
3051 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
Yun Park199c2ed2017-10-02 11:24:22 -07003052 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
jge62037862016-12-09 10:44:33 +08003053 msg->name, meta.msg_type);
3054 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
3055 if (ret) {
3056 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3057 "%s: Evt: %d fail:%d",
3058 msg->name, meta.msg_type, ret);
3059 qdf_mem_free(msg);
3060 return ret;
3061 }
3062
3063 hdd_ipa->stats.num_send_msg++;
3064
3065 return ret;
3066}
3067
3068/**
3069 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3070 * @hdd_ctx: pointer to hdd adapter
3071 *
3072 * Send disconnect client event to IPA driver during SSR
3073 *
3074 * Return: 0 - Success
3075 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003076static int hdd_ipa_uc_disconnect_client(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003077{
3078 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3079 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303080 int i;
3081
Yun Park199c2ed2017-10-02 11:24:22 -07003082 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Govind Singh9c58eba2016-09-02 16:23:06 +05303083 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003084 if (qdf_is_macaddr_broadcast(&adapter->sta_info[i].sta_mac))
Govind Singh9c58eba2016-09-02 16:23:06 +05303085 continue;
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003086 if ((adapter->sta_info[i].in_use) &&
3087 (!adapter->sta_info[i].is_deauth_in_progress) &&
jge62037862016-12-09 10:44:33 +08003088 hdd_ipa->sap_num_connected_sta) {
3089 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003090 adapter->sta_info[i].sta_mac.bytes);
jge62037862016-12-09 10:44:33 +08003091 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303092 }
3093 }
Yun Park199c2ed2017-10-02 11:24:22 -07003094 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07003095 hdd_ipa->sap_num_connected_sta);
Govind Singh9c58eba2016-09-02 16:23:06 +05303096
3097 return ret;
3098}
3099
3100/**
jge62037862016-12-09 10:44:33 +08003101 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3102 * @hdd_ctx: pointer to hdd adapter
3103 *
3104 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303105 *
3106 * Return: 0 - Success
3107 */
jge62037862016-12-09 10:44:33 +08003108
Jeff Johnson49d45e62017-08-29 14:30:42 -07003109static int hdd_ipa_uc_disconnect_ap(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003110{
3111 int ret = 0;
3112
Yun Park199c2ed2017-10-02 11:24:22 -07003113 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003114 if (adapter->ipa_context) {
jge62037862016-12-09 10:44:33 +08003115 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3116 adapter->dev->dev_addr);
Yun Parkfec73dc2017-09-06 10:40:07 -07003117 }
Yun Park199c2ed2017-10-02 11:24:22 -07003118 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
jge62037862016-12-09 10:44:33 +08003119
3120 return ret;
3121}
3122
jge62037862016-12-09 10:44:33 +08003123/**
3124 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3125 * @hdd_ctx: pointer to hdd adapter
3126 *
3127 * Send disconnect sta event to IPA driver during SSR
3128 *
3129 * Return: 0 - Success
3130 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003131static int hdd_ipa_uc_disconnect_sta(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003132{
Jeff Johnsond377dce2017-10-04 10:32:42 -07003133 struct hdd_station_ctx *sta_ctx;
jge62037862016-12-09 10:44:33 +08003134 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3135 int ret = 0;
3136
Yun Park199c2ed2017-10-02 11:24:22 -07003137 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003138 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003139 hdd_ipa->sta_connected) {
Jeff Johnsond377dce2017-10-04 10:32:42 -07003140 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
jge62037862016-12-09 10:44:33 +08003141 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Jeff Johnsond377dce2017-10-04 10:32:42 -07003142 sta_ctx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003143 }
Yun Park199c2ed2017-10-02 11:24:22 -07003144 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
jge62037862016-12-09 10:44:33 +08003145
3146 return ret;
3147}
jge62037862016-12-09 10:44:33 +08003148
3149/**
3150 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3151 * @hdd_ctx: pointer to hdd context
3152 *
3153 * Send disconnect event to IPA driver during SSR
3154 *
3155 * Return: 0 - Success
3156 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003157static int hdd_ipa_uc_disconnect(struct hdd_context *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303158{
3159 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
3160 QDF_STATUS status;
Jeff Johnson49d45e62017-08-29 14:30:42 -07003161 struct hdd_adapter *adapter;
Govind Singh9c58eba2016-09-02 16:23:06 +05303162 int ret = 0;
3163
Govind Singh9c58eba2016-09-02 16:23:06 +05303164 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
3165 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Jeff Johnson57eb2732017-10-02 11:40:20 -07003166 adapter = adapter_node->adapter;
jge62037862016-12-09 10:44:33 +08003167 if (adapter->device_mode == QDF_SAP_MODE) {
3168 hdd_ipa_uc_disconnect_client(adapter);
3169 hdd_ipa_uc_disconnect_ap(adapter);
3170 } else if (adapter->device_mode == QDF_STA_MODE) {
3171 hdd_ipa_uc_disconnect_sta(adapter);
3172 }
3173
Govind Singh9c58eba2016-09-02 16:23:06 +05303174 status = hdd_get_next_adapter(
3175 hdd_ctx, adapter_node, &next);
3176 adapter_node = next;
3177 }
3178
3179 return ret;
3180}
3181
3182/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003183 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003184 *
3185 * Deinit basic IPA UC host side to be in sync reloaded FW during
3186 * SSR
3187 *
3188 * Return: 0 - Success
3189 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003190static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003191{
3192 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3193 int idx;
3194 struct hdd_ipa_iface_context *iface_context;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003195 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003196
Yun Park199c2ed2017-10-02 11:24:22 -07003197 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003198
Arun Khandavallicc544b32017-01-30 19:52:16 +05303199 if (!hdd_ipa)
3200 return 0;
3201
3202 hdd_ctx = hdd_ipa->hdd_ctx;
3203 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003204 return 0;
3205
jge62037862016-12-09 10:44:33 +08003206 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303207 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003208
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003209 /* Clean up HDD IPA interfaces */
3210 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3211 (idx < HDD_IPA_MAX_IFACE); idx++) {
3212 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003213 if (iface_context->adapter && iface_context->adapter->magic ==
3214 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003215 hdd_ipa_cleanup_iface(iface_context);
3216 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003217 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003218 /* After SSR, wlan driver reloads FW again. But we need to protect
3219 * IPA submodule during SSR transient state. So deinit basic IPA
3220 * UC host side to be in sync with reloaded FW during SSR
3221 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003222
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303223 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003224 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3225 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3226 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3227 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303228 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003229
Guolei Bianca144d82016-11-10 11:07:42 +08003230 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3231 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3232
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003233 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
3234 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
3235 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
3236 hdd_ipa->uc_op_work[idx].msg = NULL;
3237 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003238
Yun Park199c2ed2017-10-02 11:24:22 -07003239 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003240 return 0;
3241}
3242
3243/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003244 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3245 *
3246 * Deinit basic IPA UC host side to be in sync reloaded FW during
3247 * SSR
3248 *
3249 * Return: 0 - Success
3250 */
3251int hdd_ipa_uc_ssr_deinit(void)
3252{
3253 int ret;
3254
3255 cds_ssr_protect(__func__);
3256 ret = __hdd_ipa_uc_ssr_deinit();
3257 cds_ssr_unprotect(__func__);
3258
3259 return ret;
3260}
3261
3262/**
3263 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003264 *
3265 * Init basic IPA UC host side to be in sync with reloaded FW after
3266 * SSR to resume IPA UC operations
3267 *
3268 * Return: 0 - Success
3269 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003270static int __hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003271{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272
Arun Khandavallicc544b32017-01-30 19:52:16 +05303273 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3274 int i;
3275 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303276
Yun Park199c2ed2017-10-02 11:24:22 -07003277 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003278
Arun Khandavallicc544b32017-01-30 19:52:16 +05303279 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3280 return 0;
3281
Arun Khandavallicc544b32017-01-30 19:52:16 +05303282 /* Create the interface context */
3283 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3284 iface_context = &hdd_ipa->iface_context[i];
3285 iface_context->hdd_ipa = hdd_ipa;
3286 iface_context->cons_client =
3287 hdd_ipa_adapter_2_client[i].cons_client;
3288 iface_context->prod_client =
3289 hdd_ipa_adapter_2_client[i].prod_client;
3290 iface_context->iface_id = i;
3291 iface_context->adapter = NULL;
3292 }
3293 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3294 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3295 hdd_ipa->vdev_offload_enabled[i] = false;
3296 }
3297
3298 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3299 hdd_ipa->resource_loading = false;
3300 hdd_ipa->resource_unloading = false;
3301 hdd_ipa->sta_connected = 0;
3302 hdd_ipa->ipa_pipes_down = true;
3303 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303304 }
3305
Yun Park199c2ed2017-10-02 11:24:22 -07003306 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003307 return 0;
3308}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003309
3310/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003311 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3312 *
3313 * Init basic IPA UC host side to be in sync with reloaded FW after
3314 * SSR to resume IPA UC operations
3315 *
3316 * Return: 0 - Success
3317 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003318int hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003319{
3320 int ret;
3321
3322 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303323 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003324 cds_ssr_unprotect(__func__);
3325
3326 return ret;
3327}
3328
3329/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003330 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3331 * @work: scheduled work
3332 *
3333 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3334 * not want to immediately release the wake lock since the system
3335 * would then potentially try to suspend when there is a healthy data
3336 * rate. Deferred work is scheduled and this function handles the
3337 * work. When this function is called, if the IPA resource is still
3338 * released then we release the wake lock.
3339 *
3340 * Return: None
3341 */
3342static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3343{
3344 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3345 struct hdd_ipa_priv,
3346 wake_lock_work);
3347
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303348 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003349
3350 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3351 goto end;
3352
3353 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303354 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003355 WIFI_POWER_EVENT_WAKELOCK_IPA);
3356
3357end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303358 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003359}
3360
3361/**
3362 * hdd_ipa_rm_request() - Request resource from IPA
3363 * @hdd_ipa: Global HDD IPA context
3364 *
3365 * Return: 0 on success, negative errno on error
3366 */
3367static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3368{
3369 int ret = 0;
3370
3371 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3372 return 0;
3373
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303374 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003375
3376 switch (hdd_ipa->rm_state) {
3377 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303378 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003379 return 0;
3380 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303381 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003382 return -EINPROGRESS;
3383 case HDD_IPA_RM_RELEASED:
3384 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3385 break;
3386 }
3387
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303388 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003389
3390 ret = ipa_rm_inactivity_timer_request_resource(
3391 IPA_RM_RESOURCE_WLAN_PROD);
3392
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303393 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003394 if (ret == 0) {
3395 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3396 hdd_ipa->stats.num_rm_grant_imm++;
3397 }
3398
3399 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3400 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303401 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003402 WIFI_POWER_EVENT_WAKELOCK_IPA);
3403 hdd_ipa->wake_lock_released = false;
3404 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303405 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003406
3407 return ret;
3408}
3409
3410/**
3411 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3412 * @hdd_ipa: Global HDD IPA context
3413 *
3414 * Return: 0 if resources released, negative errno otherwise
3415 */
3416static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3417{
3418 int ret = 0;
3419
3420 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3421 return 0;
3422
3423 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3424 return -EAGAIN;
3425
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303426 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003427
Nirav Shahcbc6d722016-03-01 16:24:53 +05303428 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303429 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003430 return -EAGAIN;
3431 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303432 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303434 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003435 switch (hdd_ipa->rm_state) {
3436 case HDD_IPA_RM_GRANTED:
3437 break;
3438 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303439 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003440 return -EINPROGRESS;
3441 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303442 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003443 return 0;
3444 }
3445
3446 /* IPA driver returns immediately so set the state here to avoid any
3447 * race condition.
3448 */
3449 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3450 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303451 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003453 ret = ipa_rm_inactivity_timer_release_resource(
3454 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003455
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303456 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457 if (unlikely(ret != 0)) {
3458 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3459 WARN_ON(1);
Yun Park199c2ed2017-10-02 11:24:22 -07003460 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
3461 "ipa_rm_inactivity_timer_release_resource returnied fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003462 }
3463
3464 /*
3465 * If wake_lock is released immediately, kernel would try to suspend
3466 * immediately as well, Just avoid ping-pong between suspend-resume
3467 * while there is healthy amount of data transfer going on by
3468 * releasing the wake_lock after some delay.
3469 */
3470 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3471 msecs_to_jiffies
3472 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3473
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303474 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003475
3476 return ret;
3477}
3478
3479/**
3480 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3481 * @user_data: user data registered with IPA
3482 * @event: the IPA resource manager event that occurred
3483 * @data: the data associated with the event
3484 *
3485 * Return: None
3486 */
3487static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3488 unsigned long data)
3489{
3490 struct hdd_ipa_priv *hdd_ipa = user_data;
3491
3492 if (unlikely(!hdd_ipa))
3493 return;
3494
3495 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3496 return;
3497
Srinivas Girigowda97852372017-03-06 16:52:59 -08003498 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003499
3500 switch (event) {
3501 case IPA_RM_RESOURCE_GRANTED:
3502 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3503 /* RM Notification comes with ISR context
3504 * it should be serialized into work queue to avoid
3505 * ISR sleep problem
3506 */
3507 hdd_ipa->uc_rm_work.event = event;
3508 schedule_work(&hdd_ipa->uc_rm_work.work);
3509 break;
3510 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303511 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003512 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303513 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003514 hdd_ipa->stats.num_rm_grant++;
3515 break;
3516
3517 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003518 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003519 hdd_ipa->resource_unloading = false;
3520 break;
3521
3522 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303523 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524 break;
3525 }
3526}
3527
3528/**
3529 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3530 *
3531 * Callback function registered with IPA that is called when IPA wants
3532 * to release the WLAN consumer resource
3533 *
3534 * Return: 0 if the request is granted, negative errno otherwise
3535 */
3536static int hdd_ipa_rm_cons_release(void)
3537{
3538 return 0;
3539}
3540
3541/**
3542 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3543 *
3544 * Callback function registered with IPA that is called when IPA wants
3545 * to access the WLAN consumer resource
3546 *
3547 * Return: 0 if the request is granted, negative errno otherwise
3548 */
3549static int hdd_ipa_rm_cons_request(void)
3550{
Yun Park4d8b60a2015-10-22 13:59:32 -07003551 int ret = 0;
3552
3553 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303554 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003555 "IPA resource loading in progress");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003556 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003557 ret = -EINPROGRESS;
3558 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303559 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003560 "IPA resource unloading in progress");
Yun Park4d8b60a2015-10-22 13:59:32 -07003561 ghdd_ipa->pending_cons_req = true;
3562 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003563 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003564
3565 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003566}
3567
3568/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003569 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003570 * @hdd_ctx: Global HDD context
3571 * @tx_packets: Number of packets transmitted in the last sample period
3572 * @rx_packets: Number of packets received in the last sample period
3573 *
3574 * Return: 0 on success, negative errno on error
3575 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07003576static int __hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx,
3577 uint64_t tx_packets,
3578 uint64_t rx_packets)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003579{
3580 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003581 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003582 struct ipa_rm_perf_profile profile;
Yun Parkb4f591d2017-03-29 15:51:01 -07003583 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003584 int ret;
3585
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003586 if (wlan_hdd_validate_context(hdd_ctx))
3587 return 0;
3588
3589 hdd_ipa = hdd_ctx->hdd_ipa;
3590
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003591 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3592 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3593 return 0;
3594
3595 memset(&profile, 0, sizeof(profile));
3596
3597 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3598 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3599 else if (tx_packets >
3600 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3601 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3602 else
3603 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3604
3605 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3606 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3607 else if (rx_packets >
3608 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3609 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3610 else
3611 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3612
Yun Parkec845302016-12-15 09:22:57 -08003613 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003614 "CONS perf curr: %d, next: %d",
3615 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003616 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003617 "PROD perf curr: %d, next: %d",
3618 hdd_ipa->curr_prod_bw, next_prod_bw);
3619
3620 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003621 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003622 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003623 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS,
3624 next_cons_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003625 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003626 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003627
3628 return ret;
3629 }
3630 hdd_ipa->curr_cons_bw = next_cons_bw;
3631 hdd_ipa->stats.num_cons_perf_req++;
3632 }
3633
3634 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003635 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636 hdd_ipa->curr_prod_bw, next_prod_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003637 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD,
3638 next_prod_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003639 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003640 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003641 return ret;
3642 }
3643 hdd_ipa->curr_prod_bw = next_prod_bw;
3644 hdd_ipa->stats.num_prod_perf_req++;
3645 }
3646
3647 return 0;
3648}
3649
3650/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003651 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3652 * @hdd_ctx: Global HDD context
3653 * @tx_packets: Number of packets transmitted in the last sample period
3654 * @rx_packets: Number of packets received in the last sample period
3655 *
3656 * Return: 0 on success, negative errno on error
3657 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003658int hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003659 uint64_t rx_packets)
3660{
3661 int ret;
3662
3663 cds_ssr_protect(__func__);
3664 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3665 cds_ssr_unprotect(__func__);
3666
3667 return ret;
3668}
3669
3670/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003671 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3672 * @work: struct work_struct
3673 * @work_handler: work_handler
3674 *
3675 * Return: none
3676 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003677static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3678 work_func_t work_handler)
3679{
3680 INIT_WORK(work, work_handler);
3681}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003682
3683/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684 * hdd_ipa_setup_rm() - Setup IPA resource management
3685 * @hdd_ipa: Global HDD IPA context
3686 *
3687 * Return: 0 on success, negative errno on error
3688 */
3689static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3690{
3691 struct ipa_rm_create_params create_params = { 0 };
3692 int ret;
3693
3694 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3695 return 0;
3696
Rajeev Kumar217f2172016-01-06 18:11:55 -08003697 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3698 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003699 memset(&create_params, 0, sizeof(create_params));
3700 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3701 create_params.reg_params.user_data = hdd_ipa;
3702 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3703 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3704
3705 ret = ipa_rm_create_resource(&create_params);
3706 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303707 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708 "Create RM resource failed: %d", ret);
3709 goto setup_rm_fail;
3710 }
3711
3712 memset(&create_params, 0, sizeof(create_params));
3713 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3714 create_params.request_resource = hdd_ipa_rm_cons_request;
3715 create_params.release_resource = hdd_ipa_rm_cons_release;
3716 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3717
3718 ret = ipa_rm_create_resource(&create_params);
3719 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303720 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003721 "Create RM CONS resource failed: %d", ret);
3722 goto delete_prod;
3723 }
3724
3725 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3726 IPA_RM_RESOURCE_APPS_CONS);
3727
3728 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3729 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3730 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303731 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003732 ret);
3733 goto timer_init_failed;
3734 }
3735
3736 /* Set the lowest bandwidth to start with */
3737 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3738
3739 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303740 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003741 "Set perf level failed: %d", ret);
3742 goto set_perf_failed;
3743 }
3744
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303745 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003746 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3747 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303748 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003749 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3750 hdd_ipa->wake_lock_released = true;
3751 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3752
3753 return ret;
3754
3755set_perf_failed:
3756 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3757
3758timer_init_failed:
3759 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3760
3761delete_prod:
3762 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3763
3764setup_rm_fail:
3765 return ret;
3766}
3767
3768/**
3769 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3770 * @hdd_ipa: Global HDD IPA context
3771 *
3772 * Destroys all resources associated with the IPA resource manager
3773 *
3774 * Return: None
3775 */
3776static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3777{
3778 int ret;
3779
3780 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3781 return;
3782
3783 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303784 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003785
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003786 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303787 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003788
3789 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3790
3791 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3792 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303793 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003794 "RM PROD resource delete failed %d", ret);
3795
3796 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3797 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303798 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003799 "RM CONS resource delete failed %d", ret);
3800}
3801
tfyu0380a972017-07-13 18:19:37 +08003802#ifdef QCA_CONFIG_SMP
3803static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
3804{
3805 return netif_rx_ni(skb);
3806}
3807#else
3808static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
3809{
3810 struct iphdr *ip_h;
3811 static atomic_t softirq_mitigation_cntr =
3812 ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH);
3813 int result;
3814
3815 ip_h = (struct iphdr *)(skb->data);
3816 if ((skb->protocol == htons(ETH_P_IP)) &&
3817 (ip_h->protocol == IPPROTO_ICMP)) {
3818 result = netif_rx_ni(skb);
3819 } else {
3820 /* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets
3821 * to avoid excessive softirq's.
3822 */
3823 if (atomic_dec_and_test(&softirq_mitigation_cntr)) {
3824 result = netif_rx_ni(skb);
3825 atomic_set(&softirq_mitigation_cntr,
3826 IPA_WLAN_RX_SOFTIRQ_THRESH);
3827 } else {
3828 result = netif_rx(skb);
3829 }
3830 }
3831
3832 return result;
3833}
3834#endif
3835
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003836/**
3837 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3838 * @skb: network buffer
3839 * @adapter: network adapter
3840 *
3841 * Called when a network buffer is received which should not be routed
3842 * to the IPA module.
3843 *
3844 * Return: None
3845 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303846static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Jeff Johnson49d45e62017-08-29 14:30:42 -07003847 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003848{
tfyu0380a972017-07-13 18:19:37 +08003849 int result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003850 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3851 unsigned int cpu_index;
3852
3853 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Jeff Johnson36e74c42017-09-18 08:15:42 -07003854 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%pK",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003855 adapter);
3856 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003857 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858 return;
3859 }
3860
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003861 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003862 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003863 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003864 return;
3865 }
3866
3867 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3868 skb->dev = adapter->dev;
3869 skb->protocol = eth_type_trans(skb, skb->dev);
3870 skb->ip_summed = CHECKSUM_NONE;
3871
3872 cpu_index = wlan_hdd_get_cpu();
3873
Jeff Johnson6ced42c2017-10-20 12:48:11 -07003874 ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index];
tfyu0380a972017-07-13 18:19:37 +08003875 result = hdd_ipa_aggregated_rx_ind(skb);
3876 if (result == NET_RX_SUCCESS)
Jeff Johnson6ced42c2017-10-20 12:48:11 -07003877 ++adapter->hdd_stats.tx_rx_stats.rx_delivered[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003878 else
Jeff Johnson6ced42c2017-10-20 12:48:11 -07003879 ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003880
3881 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003882}
3883
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003884/**
Leo Chang69c39692016-10-12 20:11:12 -07003885 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3886 * @hdd_ipa: pointer to hdd ipa context
3887 * @adapter: network adapter
3888 * @skb: data pointer
3889 *
3890 * if exception packet has set forward bit, copied new packet should be
3891 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3892 * put into pm queue and tx procedure will be differed
3893 *
3894 * Return: None
3895 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003896static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07003897 struct hdd_adapter *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003898{
Leo Chang69c39692016-10-12 20:11:12 -07003899 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3900
Leo Chang69c39692016-10-12 20:11:12 -07003901 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Yun Park01deb2c2017-06-14 15:21:44 -07003902
3903 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
3904 qdf_nbuf_ipa_owned_set(skb);
3905
Leo Chang69c39692016-10-12 20:11:12 -07003906 /* WLAN subsystem is in suspend, put int queue */
3907 if (hdd_ipa->suspended) {
3908 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3909 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3910 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003911 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3912 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003913 pm_tx_cb->exception = true;
3914 pm_tx_cb->adapter = adapter;
3915 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003916 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003917 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3918 hdd_ipa->stats.num_tx_queued++;
3919 } else {
3920 /* Resume, put packet into WLAN TX */
3921 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003922 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003923 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3924 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003925 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003926 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003927 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003928 hdd_ipa->ipa_tx_forward++;
3929 }
3930 }
3931}
3932
3933/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003934 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3935 * @hdd_ipa: pointer to HDD IPA struct
3936 * @adapter: hdd adapter pointer
3937 * @desc: Firmware descriptor
3938 * @skb: Data buffer
3939 *
3940 * Return:
3941 * HDD_IPA_FORWARD_PKT_NONE
3942 * HDD_IPA_FORWARD_PKT_DISCARD
3943 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3944 *
3945 */
3946
3947static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3948 struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07003949 struct hdd_adapter *adapter,
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003950 uint8_t desc,
3951 qdf_nbuf_t skb)
3952{
3953 int ret = HDD_IPA_FORWARD_PKT_NONE;
Yun Park0dad1002017-07-14 14:57:01 -07003954 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3955 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003956
3957 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303958 if (!ol_txrx_fwd_desc_thresh_check(
Yun Park0dad1002017-07-14 14:57:01 -07003959 (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc,
3960 (struct cdp_pdev *)pdev,
3961 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303962 /* Drop the packet*/
3963 hdd_ipa->stats.num_tx_fwd_err++;
3964 kfree_skb(skb);
3965 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3966 return ret;
3967 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003968 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3969 "Forward packet to Tx (fw_desc=%d)", desc);
3970 hdd_ipa->ipa_tx_forward++;
3971
3972 if ((desc & FW_RX_DESC_DISCARD_M)) {
3973 hdd_ipa_forward(hdd_ipa, adapter, skb);
3974 hdd_ipa->ipa_rx_internel_drop_count++;
3975 hdd_ipa->ipa_rx_discard++;
3976 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3977 } else {
3978 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003979
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003980 if (cloned_skb)
3981 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3982 else
3983 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3984 "%s: tx skb alloc failed",
3985 __func__);
3986 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3987 }
3988 }
3989
3990 return ret;
3991}
3992
3993/**
Yun Park637d6482016-10-05 10:51:33 -07003994 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003995 * @priv: pointer to private data registered with IPA (we register a
3996 * pointer to the global IPA context)
3997 * @evt: the IPA event which triggered the callback
3998 * @data: data associated with the event
3999 *
4000 * Return: None
4001 */
Yun Parkf8d6a122016-10-11 15:49:43 -07004002static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004003 unsigned long data)
4004{
4005 struct hdd_ipa_priv *hdd_ipa = NULL;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004006 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304007 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004008 uint8_t iface_id;
4009 uint8_t session_id;
4010 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004011 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07004012 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004013
4014 hdd_ipa = (struct hdd_ipa_priv *)priv;
4015
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08004016 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
4017 return;
4018
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004019 switch (evt) {
4020 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05304021 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07004022
4023 /*
4024 * When SSR is going on or driver is unloading,
4025 * just drop the packets.
4026 */
4027 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4028 if (0 != status) {
4029 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4030 "Invalid context: drop packet");
4031 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4032 kfree_skb(skb);
4033 return;
4034 }
4035
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004036 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4037 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004038 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004039 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004040 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4041 session_id, iface_id);
4042 } else {
4043 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4044 }
4045
4046 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304047 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004048 "IPA_RECEIVE: Invalid iface_id: %u",
4049 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004050 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004051 "w2i -- skb",
4052 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004053 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004054 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004055 return;
4056 }
4057
4058 iface_context = &hdd_ipa->iface_context[iface_id];
4059 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08004060 if (!adapter) {
4061 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4062 "IPA_RECEIVE: Adapter is NULL");
4063 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4064 kfree_skb(skb);
4065 return;
4066 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004067
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304068 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004069 "w2i -- skb",
4070 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4072 hdd_ipa->stats.num_rx_excep++;
4073 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4074 } else {
4075 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4076 }
4077
4078 iface_context->stats.num_rx_ipa_excep++;
4079
4080 /* Disable to forward Intra-BSS Rx packets when
4081 * ap_isolate=1 in hostapd.conf
4082 */
Yun Park046101c2016-09-02 15:32:14 -07004083 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004084 /*
4085 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4086 * all Rx packets to IPA uC, which need to be forwarded
4087 * to other interface.
4088 * And, IPA driver will send back to WLAN host driver
4089 * through exception pipe with fw_desc field set by FW.
4090 * Here we are checking fw_desc field for FORWARD bit
4091 * set, and forward to Tx. Then copy to kernel stack
4092 * only when DISCARD bit is not set.
4093 */
4094 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004095 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4096 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4097 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004098 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004099 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004100 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004101 "Intra-BSS FWD is disabled-skip forward to Tx");
4102 }
4103
4104 hdd_ipa_send_skb_to_network(skb, adapter);
4105 break;
4106
4107 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304108 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004109 "w2i cb wrong event: 0x%x", evt);
4110 return;
4111 }
4112}
4113
4114/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004115 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4116 * @priv: pointer to private data registered with IPA (we register a
4117 * pointer to the global IPA context)
4118 * @evt: the IPA event which triggered the callback
4119 * @data: data associated with the event
4120 *
4121 * Return: None
4122 */
4123static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
4124 unsigned long data)
4125{
4126 cds_ssr_protect(__func__);
4127 __hdd_ipa_w2i_cb(priv, evt, data);
4128 cds_ssr_unprotect(__func__);
4129}
4130
4131/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004132 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4133 * @skb: packet buffer which was transmitted
4134 *
4135 * Return: None
4136 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304137void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004138{
4139 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park52b2b992016-09-22 15:49:51 -07004140 struct ipa_rx_data *ipa_tx_desc;
4141 struct hdd_ipa_tx_desc *tx_desc;
4142 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004143
Yun Park52b2b992016-09-22 15:49:51 -07004144 if (!qdf_nbuf_ipa_owned_get(skb)) {
4145 dev_kfree_skb_any(skb);
4146 return;
4147 }
4148
4149 /* Get Tx desc pointer from SKB CB */
4150 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4151 tx_desc = hdd_ipa->tx_desc_list + id;
4152 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4153
4154 /* Return Tx Desc to IPA */
4155 ipa_free_skb(ipa_tx_desc);
4156
4157 /* Return to free tx desc list */
4158 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4159 tx_desc->ipa_tx_desc_ptr = NULL;
4160 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4161 hdd_ipa->stats.num_tx_desc_q_cnt--;
4162 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004163
4164 hdd_ipa->stats.num_tx_comp_cnt++;
4165
4166 atomic_dec(&hdd_ipa->tx_ref_cnt);
4167
4168 hdd_ipa_rm_try_release(hdd_ipa);
4169}
4170
4171/**
4172 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4173 * @iface_context: interface-specific IPA context
4174 * @ipa_tx_desc: packet data descriptor
4175 *
4176 * Return: None
4177 */
4178static void hdd_ipa_send_pkt_to_tl(
4179 struct hdd_ipa_iface_context *iface_context,
4180 struct ipa_rx_data *ipa_tx_desc)
4181{
4182 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004183 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304184 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004185 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004186
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304187 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004188 adapter = iface_context->adapter;
4189 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304190 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004191 ipa_free_skb(ipa_tx_desc);
4192 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304193 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004194 hdd_ipa_rm_try_release(hdd_ipa);
4195 return;
4196 }
4197
4198 /*
4199 * During CAC period, data packets shouldn't be sent over the air so
4200 * drop all the packets here
4201 */
hqu70708ab2017-10-10 17:52:01 +08004202 if (QDF_SAP_MODE == adapter->device_mode ||
4203 QDF_P2P_GO_MODE == adapter->device_mode) {
4204 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4205 ipa_free_skb(ipa_tx_desc);
4206 qdf_spin_unlock_bh(&iface_context->interface_lock);
4207 iface_context->stats.num_tx_cac_drop++;
4208 hdd_ipa_rm_try_release(hdd_ipa);
4209 return;
4210 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004211 }
4212
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004213 ++adapter->stats.tx_packets;
4214
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304215 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004216
4217 skb = ipa_tx_desc->skb;
4218
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304219 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004220
4221 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304222 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004223 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304224 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004225 ipa_tx_desc->dma_addr
4226 + HDD_IPA_WLAN_FRAG_HEADER
4227 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004228 ipa_tx_desc->skb->len -=
4229 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4230 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304231 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004232
Yun Park52b2b992016-09-22 15:49:51 -07004233 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4234 /* get free Tx desc and assign ipa_tx_desc pointer */
4235 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4236 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4237 struct hdd_ipa_tx_desc, link);
4238 list_del(&tx_desc->link);
4239 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4240 hdd_ipa->stats.num_tx_desc_q_cnt++;
4241 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4242 /* Store Tx Desc index into SKB CB */
4243 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4244 } else {
4245 hdd_ipa->stats.num_tx_desc_error++;
4246 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4247 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "No free Tx desc!");
4248 ipa_free_skb(ipa_tx_desc);
4249 hdd_ipa_rm_try_release(hdd_ipa);
4250 return;
4251 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004252
4253 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
4254
Leo Changfdb45c32016-10-28 11:09:23 -07004255 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004256 (struct cdp_vdev *)iface_context->tl_context,
4257 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004258 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304259 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
jiad05c1e812017-08-01 16:48:52 +08004260 qdf_nbuf_free(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004261 iface_context->stats.num_tx_err++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004262 return;
4263 }
4264
4265 atomic_inc(&hdd_ipa->tx_ref_cnt);
4266
4267 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004268}
4269
4270/**
Leo Chang11545d62016-10-17 14:53:50 -07004271 * hdd_ipa_is_present() - get IPA hw status
4272 * @hdd_ctx: pointer to hdd context
4273 *
4274 * ipa_uc_reg_rdyCB is not directly designed to check
4275 * ipa hw status. This is an undocumented function which
4276 * has confirmed with IPA team.
4277 *
4278 * Return: true - ipa hw present
4279 * false - ipa hw not present
4280 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004281bool hdd_ipa_is_present(struct hdd_context *hdd_ctx)
Leo Chang11545d62016-10-17 14:53:50 -07004282{
4283 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004284 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004285 return true;
4286 else
4287 return false;
4288}
4289
4290/**
Leo Chang69c39692016-10-12 20:11:12 -07004291 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004292 * @work: pointer to the scheduled work
4293 *
4294 * Called during PM resume to send packets to TL which were queued
4295 * while host was in the process of suspending.
4296 *
4297 * Return: None
4298 */
Leo Chang69c39692016-10-12 20:11:12 -07004299static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004300{
4301 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4302 struct hdd_ipa_priv,
4303 pm_work);
4304 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304305 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004306 uint32_t dequeued = 0;
4307
Leo Chang69c39692016-10-12 20:11:12 -07004308 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4309 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304310 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304311 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4312 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304313 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004314
4315 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004316 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004317 if (pm_tx_cb->exception) {
4318 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4319 "FLUSH EXCEPTION");
Govind Singh1dab23b2017-08-12 13:31:00 +05304320 if (pm_tx_cb->adapter->dev)
4321 hdd_softap_hard_start_xmit(skb,
4322 pm_tx_cb->adapter->dev);
Govind Singh02075942017-08-15 11:13:28 +05304323 else
4324 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004325 } else {
4326 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004327 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004328 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304329 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004330 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304331 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004332 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4333 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334
4335 hdd_ipa->stats.num_tx_dequeued += dequeued;
4336 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4337 hdd_ipa->stats.num_max_pm_queue = dequeued;
4338}
4339
4340/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004341 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004342 * @priv: pointer to private data registered with IPA (we register a
4343 * pointer to the interface-specific IPA context)
4344 * @evt: the IPA event which triggered the callback
4345 * @data: data associated with the event
4346 *
4347 * Return: None
4348 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004349static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004350 unsigned long data)
4351{
4352 struct hdd_ipa_priv *hdd_ipa = NULL;
4353 struct ipa_rx_data *ipa_tx_desc;
4354 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304355 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004356 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304357 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004358
Mukul Sharma81661ae2015-10-30 20:26:02 +05304359 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004360 ipa_tx_desc = (struct ipa_rx_data *)data;
4361 hdd_ipa = iface_context->hdd_ipa;
4362
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004364 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4365 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004366 iface_context->stats.num_tx_drop++;
4367 return;
4368 }
4369
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370 /*
4371 * When SSR is going on or driver is unloading, just drop the packets.
4372 * During SSR, there is no use in queueing the packets as STA has to
4373 * connect back any way
4374 */
4375 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304376 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004377 ipa_free_skb(ipa_tx_desc);
4378 iface_context->stats.num_tx_drop++;
4379 return;
4380 }
4381
4382 skb = ipa_tx_desc->skb;
4383
Yun Parkb187d542016-11-14 18:10:04 -08004384 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4385 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386
4387 /*
4388 * If PROD resource is not requested here then there may be cases where
4389 * IPA hardware may be clocked down because of not having proper
4390 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4391 * workaround to request PROD resource while data is going over CONS
4392 * pipe to prevent the IPA hardware clockdown.
4393 */
4394 hdd_ipa_rm_request(hdd_ipa);
4395
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304396 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004397 /*
4398 * If host is still suspended then queue the packets and these will be
4399 * drained later when resume completes. When packet is arrived here and
4400 * host is suspended, this means that there is already resume is in
4401 * progress.
4402 */
4403 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304404 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004405 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4406 pm_tx_cb->iface_context = iface_context;
4407 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304408 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004409 hdd_ipa->stats.num_tx_queued++;
4410
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304411 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004412 return;
4413 }
4414
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304415 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004416
4417 /*
4418 * If we are here means, host is not suspended, wait for the work queue
4419 * to finish.
4420 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004421 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004422
4423 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4424}
4425
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004426/*
4427 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4428 * @priv: pointer to private data registered with IPA (we register a
4429 * pointer to the interface-specific IPA context)
4430 * @evt: the IPA event which triggered the callback
4431 * @data: data associated with the event
4432 *
4433 * Return: None
4434 */
4435static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
4436 unsigned long data)
4437{
4438 cds_ssr_protect(__func__);
4439 __hdd_ipa_i2w_cb(priv, evt, data);
4440 cds_ssr_unprotect(__func__);
4441}
4442
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004444 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004445 * @hdd_ctx: Global HDD context
4446 *
4447 * Return: 0 on success, negativer errno on error
4448 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004449static int __hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004450{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004451 struct hdd_ipa_priv *hdd_ipa;
4452
4453 if (wlan_hdd_validate_context(hdd_ctx))
4454 return 0;
4455
4456 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004457
4458 if (!hdd_ipa_is_enabled(hdd_ctx))
4459 return 0;
4460
4461 /*
4462 * Check if IPA is ready for suspend, If we are here means, there is
4463 * high chance that suspend would go through but just to avoid any race
4464 * condition after suspend started, these checks are conducted before
4465 * allowing to suspend.
4466 */
4467 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4468 return -EAGAIN;
4469
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304470 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471
4472 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304473 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004474 return -EAGAIN;
4475 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304476 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004477
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304478 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004479 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304480 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004481
4482 return 0;
4483}
4484
4485/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004486 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4487 * @hdd_ctx: Global HDD context
4488 *
4489 * Return: 0 on success, negativer errno on error
4490 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004491int hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004492{
4493 int ret;
4494
4495 cds_ssr_protect(__func__);
4496 ret = __hdd_ipa_suspend(hdd_ctx);
4497 cds_ssr_unprotect(__func__);
4498
4499 return ret;
4500}
4501
4502/**
4503 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004504 * hdd_ctx: Global HDD context
4505 *
4506 * Return: 0 on success, negative errno on error
4507 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004508static int __hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004509{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004510 struct hdd_ipa_priv *hdd_ipa;
4511
4512 if (wlan_hdd_validate_context(hdd_ctx))
4513 return 0;
4514
4515 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004516
4517 if (!hdd_ipa_is_enabled(hdd_ctx))
4518 return 0;
4519
4520 schedule_work(&hdd_ipa->pm_work);
4521
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304522 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004523 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304524 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004525
4526 return 0;
4527}
4528
4529/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004530 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4531 * hdd_ctx: Global HDD context
4532 *
4533 * Return: 0 on success, negative errno on error
4534 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004535int hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004536{
4537 int ret;
4538
4539 cds_ssr_protect(__func__);
4540 ret = __hdd_ipa_resume(hdd_ctx);
4541 cds_ssr_unprotect(__func__);
4542
4543 return ret;
4544}
4545
4546/**
Yun Park52b2b992016-09-22 15:49:51 -07004547 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
4548 * @hdd_ipa: Global HDD IPA context
4549 *
4550 * Return: 0 on success, negative errno on error
4551 */
4552static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
4553{
4554 int i;
4555 uint32_t max_desc_cnt;
4556 struct hdd_ipa_tx_desc *tmp_desc;
4557
Yun Parkd9c528e2017-08-30 16:34:57 -07004558 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
Yun Park52b2b992016-09-22 15:49:51 -07004559
4560 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
4561
jiad14fe4fb2017-08-08 13:33:14 +08004562 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc) *
Yun Parkd9c528e2017-08-30 16:34:57 -07004563 max_desc_cnt);
Yun Park52b2b992016-09-22 15:49:51 -07004564
4565 if (!tmp_desc) {
4566 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkd9c528e2017-08-30 16:34:57 -07004567 "Free Tx descriptor allocation failed");
Yun Park52b2b992016-09-22 15:49:51 -07004568 return -ENOMEM;
4569 }
4570
4571 hdd_ipa->tx_desc_list = tmp_desc;
4572
4573 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07004574 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07004575 tmp_desc->id = i;
4576 tmp_desc->ipa_tx_desc_ptr = NULL;
4577 list_add_tail(&tmp_desc->link,
4578 &hdd_ipa->free_tx_desc_head);
4579 tmp_desc++;
4580 }
4581
4582 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4583 hdd_ipa->stats.num_tx_desc_error = 0;
4584
4585 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4586
4587 return 0;
4588}
4589
4590/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004591 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4592 * @hdd_ipa: Global HDD IPA context
4593 *
4594 * Return: 0 on success, negative errno on error
4595 */
4596static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4597{
4598 int i, ret = 0;
4599 struct ipa_sys_connect_params *ipa;
4600 uint32_t desc_fifo_sz;
4601
4602 /* The maximum number of descriptors that can be provided to a BAM at
4603 * once is one less than the total number of descriptors that the buffer
4604 * can contain.
4605 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4606 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4607 * be provided at once.
4608 * Because of above requirement, one extra descriptor will be added to
4609 * make sure hardware always has one descriptor.
4610 */
4611 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4612 + sizeof(struct sps_iovec);
4613
4614 /*setup TX pipes */
4615 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4616 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4617
4618 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4619 ipa->desc_fifo_sz = desc_fifo_sz;
4620 ipa->priv = &hdd_ipa->iface_context[i];
4621 ipa->notify = hdd_ipa_i2w_cb;
4622
4623 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4624 ipa->ipa_ep_cfg.hdr.hdr_len =
4625 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4626 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4627 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4628 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4629 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4630 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4631 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4632 } else {
4633 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4634 }
4635 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4636
4637 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4638 ipa->keep_ipa_awake = 1;
4639
4640 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4641 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004642 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4643 "Failed for pipe %d ret: %d", i, ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644 goto setup_sys_pipe_fail;
4645 }
4646 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4647 }
4648
4649 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4650 /*
4651 * Hard code it here, this can be extended if in case
4652 * PROD pipe is also per interface.
4653 * Right now there is no advantage of doing this.
4654 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004655 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4656
Yun Parkb4f591d2017-03-29 15:51:01 -07004657 ipa->client = IPA_CLIENT_WLAN1_PROD;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658
4659 ipa->desc_fifo_sz = desc_fifo_sz;
4660 ipa->priv = hdd_ipa;
4661 ipa->notify = hdd_ipa_w2i_cb;
4662
4663 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4664 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4665 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4666 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4667
4668 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4669 ipa->keep_ipa_awake = 1;
4670
4671 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4672 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304673 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004674 "Failed for RX pipe: %d", ret);
4675 goto setup_sys_pipe_fail;
4676 }
4677 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4678 }
4679
Yun Parkd9c528e2017-08-30 16:34:57 -07004680 /* Allocate free Tx desc list */
Yun Park52b2b992016-09-22 15:49:51 -07004681 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
4682 if (ret)
4683 goto setup_sys_pipe_fail;
4684
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004685 return ret;
4686
4687setup_sys_pipe_fail:
4688
4689 while (--i >= 0) {
4690 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304691 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004692 sizeof(struct hdd_ipa_sys_pipe));
4693 }
4694
4695 return ret;
4696}
4697
4698/**
4699 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4700 * @hdd_ipa: Global HDD IPA context
4701 *
4702 * Return: None
4703 */
4704static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4705{
4706 int ret = 0, i;
Yun Parkd9c528e2017-08-30 16:34:57 -07004707 uint32_t max_desc_cnt;
Yun Park52b2b992016-09-22 15:49:51 -07004708 struct hdd_ipa_tx_desc *tmp_desc;
4709 struct ipa_rx_data *ipa_tx_desc;
4710
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004711 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4712 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
Yun Parkb4f591d2017-03-29 15:51:01 -07004713 ret = ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4714 conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004715 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304716 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004717 ret);
4718
4719 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4720 }
4721 }
Yun Park52b2b992016-09-22 15:49:51 -07004722
4723 if (hdd_ipa->tx_desc_list) {
Yun Parkd9c528e2017-08-30 16:34:57 -07004724 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
4725
Yun Park52b2b992016-09-22 15:49:51 -07004726 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07004727 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07004728 tmp_desc = hdd_ipa->tx_desc_list + i;
4729 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
4730 if (ipa_tx_desc)
4731 ipa_free_skb(ipa_tx_desc);
4732 }
4733 tmp_desc = hdd_ipa->tx_desc_list;
4734 hdd_ipa->tx_desc_list = NULL;
4735 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4736 hdd_ipa->stats.num_tx_desc_error = 0;
4737 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4738 qdf_mem_free(tmp_desc);
4739 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004740}
4741
4742/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004743 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4744 * @iface_context: interface-specific IPA context
4745 *
4746 * Return: None
4747 */
4748static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4749{
Yun Park199c2ed2017-10-02 11:24:22 -07004750 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07004751
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004752 if (iface_context == NULL)
4753 return;
Orhan K AKYILDIZ3332be32017-05-31 15:36:31 -07004754 if (iface_context->adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
4755 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
4756 "%s: bad adapter(%pK).magic(%d)!",
4757 __func__, iface_context->adapter,
4758 iface_context->adapter->magic);
4759 return;
4760 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004761
Yun Parkb4f591d2017-03-29 15:51:01 -07004762 cdp_ipa_cleanup_iface(cds_get_context(QDF_MODULE_ID_SOC),
4763 iface_context->adapter->dev->name,
4764 hdd_ipa_is_ipv6_enabled(iface_context->hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004765
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304766 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004767 iface_context->adapter->ipa_context = NULL;
4768 iface_context->adapter = NULL;
4769 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304770 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004771 iface_context->ifa_address = 0;
4772 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304773 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004774 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304775 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004776 }
4777 iface_context->hdd_ipa->num_iface--;
Yun Park199c2ed2017-10-02 11:24:22 -07004778 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07004779 iface_context->hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004780}
4781
4782/**
4783 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4784 * @hdd_ipa: HDD IPA global context
4785 * @adapter: Interface upon which IPA is being setup
4786 * @sta_id: Station ID of the API instance
4787 *
4788 * Return: 0 on success, negative errno value on error
4789 */
4790static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004791 struct hdd_adapter *adapter, uint8_t sta_id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004792{
4793 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park0dad1002017-07-14 14:57:01 -07004794 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
4795 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004796 void *tl_context = NULL;
4797 int i, ret = 0;
4798
Yun Park199c2ed2017-10-02 11:24:22 -07004799 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07004800
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004801 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4802 * channel change indication. Since these indications are sent by lower
4803 * layer as SAP updates and IPA doesn't have to do anything for these
4804 * updates so ignoring!
4805 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004806 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004807 return 0;
4808
4809 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4810 if (hdd_ipa->iface_context[i].adapter == NULL) {
4811 iface_context = &(hdd_ipa->iface_context[i]);
4812 break;
4813 }
4814 }
4815
4816 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304817 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004818 "All the IPA interfaces are in use");
4819 ret = -ENOMEM;
4820 goto end;
4821 }
4822
4823 adapter->ipa_context = iface_context;
4824 iface_context->adapter = adapter;
4825 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004826 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Yun Park0dad1002017-07-14 14:57:01 -07004827 soc, (struct cdp_pdev *)pdev, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004828 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304829 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004830 "Not able to get TL context sta_id: %d", sta_id);
4831 ret = -EINVAL;
4832 goto end;
4833 }
4834
4835 iface_context->tl_context = tl_context;
4836
Yun Parkb4f591d2017-03-29 15:51:01 -07004837 ret = cdp_ipa_setup_iface(cds_get_context(QDF_MODULE_ID_SOC),
4838 adapter->dev->name, adapter->dev->dev_addr,
4839 iface_context->prod_client,
4840 iface_context->cons_client,
4841 adapter->sessionId,
4842 hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004843 if (ret)
4844 goto end;
4845
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004846 hdd_ipa->num_iface++;
Yun Parkfec73dc2017-09-06 10:40:07 -07004847
Yun Park199c2ed2017-10-02 11:24:22 -07004848 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07004849 hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004850 return ret;
4851
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004852end:
4853 if (iface_context)
4854 hdd_ipa_cleanup_iface(iface_context);
4855 return ret;
4856}
4857
Yun Parka27049a2016-10-11 12:30:49 -07004858#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004859/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004860 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Jeff Johnson4929cd92017-10-06 19:21:57 -07004861 * @hdd_ctx: HDD context
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004862 * @mcc_mode: 0=MCC/1=SCC
4863 *
4864 * Return: 0 on success, negative errno value on error
4865 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07004866static int __hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx,
4867 bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004868{
4869 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304870 QDF_STATUS status;
Jeff Johnson089d0432017-10-02 13:27:21 -07004871 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004872 struct ipa_msg_meta meta;
4873 struct ipa_wlan_msg *msg;
4874 int ret;
4875
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004876 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004877 return -EINVAL;
4878
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004879 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4880 return -EINVAL;
4881
4882 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004883 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004884 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304885 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Jeff Johnson089d0432017-10-02 13:27:21 -07004886 adapter = adapter_node->adapter;
4887 if (adapter->device_mode == QDF_STA_MODE ||
4888 adapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004889 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnson089d0432017-10-02 13:27:21 -07004890 adapter->device_mode);
4891 hdd_deinit_tx_rx(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004892 }
4893 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004894 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004895 adapter_node = next;
4896 }
4897 }
4898
4899 /* Send SCC/MCC Switching event to IPA */
4900 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304901 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004902 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004903 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004904 return -ENOMEM;
4905 }
4906
4907 meta.msg_type = mcc_mode ?
4908 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Srinivas Girigowda97852372017-03-06 16:52:59 -08004909 hdd_debug("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004910
4911 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4912
4913 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004914 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004915 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304916 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004917 }
4918
4919 return ret;
4920}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004921
4922/**
4923 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4924 * @mcc_mode: 0=MCC/1=SCC
4925 *
4926 * Return: 0 on success, negative errno value on error
4927 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004928int hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx, bool mcc_mode)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004929{
4930 int ret;
4931
4932 cds_ssr_protect(__func__);
4933 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4934 cds_ssr_unprotect(__func__);
4935
4936 return ret;
4937}
Yun Parka27049a2016-10-11 12:30:49 -07004938#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004939
4940/**
4941 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4942 * @event: IPA WLAN event to be converted to a string
4943 *
4944 * Return: ASCII string representing the IPA WLAN event
4945 */
4946static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4947{
4948 switch (event) {
4949 case WLAN_CLIENT_CONNECT:
4950 return "WLAN_CLIENT_CONNECT";
4951 case WLAN_CLIENT_DISCONNECT:
4952 return "WLAN_CLIENT_DISCONNECT";
4953 case WLAN_CLIENT_POWER_SAVE_MODE:
4954 return "WLAN_CLIENT_POWER_SAVE_MODE";
4955 case WLAN_CLIENT_NORMAL_MODE:
4956 return "WLAN_CLIENT_NORMAL_MODE";
4957 case SW_ROUTING_ENABLE:
4958 return "SW_ROUTING_ENABLE";
4959 case SW_ROUTING_DISABLE:
4960 return "SW_ROUTING_DISABLE";
4961 case WLAN_AP_CONNECT:
4962 return "WLAN_AP_CONNECT";
4963 case WLAN_AP_DISCONNECT:
4964 return "WLAN_AP_DISCONNECT";
4965 case WLAN_STA_CONNECT:
4966 return "WLAN_STA_CONNECT";
4967 case WLAN_STA_DISCONNECT:
4968 return "WLAN_STA_DISCONNECT";
4969 case WLAN_CLIENT_CONNECT_EX:
4970 return "WLAN_CLIENT_CONNECT_EX";
4971
4972 case IPA_WLAN_EVENT_MAX:
4973 default:
4974 return "UNKNOWN";
4975 }
4976}
4977
4978/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004979 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4980 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4981 *
4982 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4983 */
4984static enum ipa_wlan_event
4985hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4986{
4987 enum ipa_wlan_event ipa_event;
4988
4989 switch (hdd_ipa_event_type) {
4990 case HDD_IPA_CLIENT_CONNECT:
4991 ipa_event = WLAN_CLIENT_CONNECT;
4992 break;
4993 case HDD_IPA_CLIENT_DISCONNECT:
4994 ipa_event = WLAN_CLIENT_DISCONNECT;
4995 break;
4996 case HDD_IPA_AP_CONNECT:
4997 ipa_event = WLAN_AP_CONNECT;
4998 break;
4999 case HDD_IPA_AP_DISCONNECT:
5000 ipa_event = WLAN_AP_DISCONNECT;
5001 break;
5002 case HDD_IPA_STA_CONNECT:
5003 ipa_event = WLAN_STA_CONNECT;
5004 break;
5005 case HDD_IPA_STA_DISCONNECT:
5006 ipa_event = WLAN_STA_DISCONNECT;
5007 break;
5008 case HDD_IPA_CLIENT_CONNECT_EX:
5009 ipa_event = WLAN_CLIENT_CONNECT_EX;
5010 break;
5011 case HDD_IPA_WLAN_EVENT_MAX:
5012 default:
5013 ipa_event = IPA_WLAN_EVENT_MAX;
5014 break;
5015 }
5016 return ipa_event;
5017
5018}
5019
5020/**
5021 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005022 * @adapter: adapter upon which the event was received
5023 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005024 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005025 * @mac_address: MAC address associated with the event
5026 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005027 * This function is meant to be called from within wlan_hdd_ipa.c
5028 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005029 * Return: 0 on success, negative errno value on error
5030 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005031static int __hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005032 enum ipa_wlan_event type, uint8_t *mac_addr)
5033{
5034 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5035 struct ipa_msg_meta meta;
5036 struct ipa_wlan_msg *msg;
5037 struct ipa_wlan_msg_ex *msg_ex = NULL;
5038 int ret;
5039
Yun Park199c2ed2017-10-02 11:24:22 -07005040 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005041 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5042 mac_addr, sta_id);
5043
5044 if (type >= IPA_WLAN_EVENT_MAX)
5045 return -EINVAL;
5046
5047 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5048 return -EINVAL;
5049
5050 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305051 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005052 return -EINVAL;
5053 }
5054
5055 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5056 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005057 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005058 return 0;
5059 }
5060
5061 /*
5062 * During IPA UC resource loading/unloading new events can be issued.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005063 */
Yun Park777d7242017-03-30 15:38:33 -07005064 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5065 (hdd_ipa->resource_loading || hdd_ipa->resource_unloading)) {
5066 unsigned int pending_event_count;
5067 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005068
Yun Park777d7242017-03-30 15:38:33 -07005069 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5070 "%s:IPA resource %s inprogress",
5071 hdd_ipa_wlan_event_to_str(type),
5072 hdd_ipa->resource_loading ?
5073 "load" : "unload");
5074
5075 /* Wait until completion of the long/unloading */
5076 ret = wait_for_completion_timeout(&hdd_ipa->ipa_resource_comp,
5077 msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME));
5078 if (!ret) {
5079 /*
5080 * If timed out, store the events separately and
5081 * handle them later.
5082 */
Yun Park64c405e2017-01-10 22:35:51 -08005083 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park777d7242017-03-30 15:38:33 -07005084 "IPA resource %s timed out",
5085 hdd_ipa->resource_loading ?
5086 "load" : "unload");
Yun Park7c4f31b2016-11-30 10:09:21 -08005087
Yun Park777d7242017-03-30 15:38:33 -07005088 if (hdd_ipa->resource_loading) {
5089 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005090
Yun Park777d7242017-03-30 15:38:33 -07005091 pending_event_count =
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005092 qdf_list_size(&hdd_ipa->pending_event);
Yun Park777d7242017-03-30 15:38:33 -07005093 if (pending_event_count >=
5094 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
5095 hdd_debug(
5096 "Reached max pending event count");
5097 qdf_list_remove_front(
5098 &hdd_ipa->pending_event,
5099 (qdf_list_node_t **)&pending_event);
5100 } else {
5101 pending_event =
5102 (struct ipa_uc_pending_event *)
5103 qdf_mem_malloc(sizeof(
5104 struct ipa_uc_pending_event));
5105 }
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005106
Yun Park777d7242017-03-30 15:38:33 -07005107 if (!pending_event) {
5108 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5109 "Pending event memory alloc fail");
5110 qdf_mutex_release(&hdd_ipa->ipa_lock);
5111 return -ENOMEM;
5112 }
5113
5114 pending_event->adapter = adapter;
5115 pending_event->sta_id = sta_id;
5116 pending_event->type = type;
5117 qdf_mem_copy(pending_event->mac_addr,
5118 mac_addr, QDF_MAC_ADDR_SIZE);
5119 qdf_list_insert_back(&hdd_ipa->pending_event,
5120 &pending_event->node);
5121
Yun Park64c405e2017-01-10 22:35:51 -08005122 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005123 }
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005124 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005125 }
Jeff Johnson4929cd92017-10-06 19:21:57 -07005126 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5127 "IPA resource %s completed",
5128 hdd_ipa->resource_loading ?
5129 "load" : "unload");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005130 }
5131
5132 hdd_ipa->stats.event[type]++;
5133
Leo Chang3bc8fed2015-11-13 10:59:47 -08005134 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005135 switch (type) {
5136 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005137 qdf_mutex_acquire(&hdd_ipa->event_lock);
5138
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005139 /* STA already connected and without disconnect, connect again
5140 * This is Roaming scenario
5141 */
5142 if (hdd_ipa->sta_connected)
5143 hdd_ipa_cleanup_iface(adapter->ipa_context);
5144
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005145 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5146 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305147 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005148 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005149 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005150
Yun Park8f289c82016-10-18 16:38:21 -07005151 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5152 (hdd_ipa->sap_num_connected_sta > 0) &&
5153 !hdd_ipa->sta_connected) {
5154 qdf_mutex_release(&hdd_ipa->event_lock);
5155 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005156 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005157 qdf_mutex_acquire(&hdd_ipa->event_lock);
5158 }
5159
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005160 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005161 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005162 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005163
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005164 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005165
5166 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005167
Yun Park199c2ed2017-10-02 11:24:22 -07005168 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005169 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005170 break;
5171
5172 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005173 qdf_mutex_acquire(&hdd_ipa->event_lock);
5174
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005175 /* For DFS channel we get two start_bss event (before and after
5176 * CAC). Also when ACS range includes both DFS and non DFS
5177 * channels, we could possibly change channel many times due to
5178 * RADAR detection and chosen channel may not be a DFS channels.
5179 * So dont return error here. Just discard the event.
5180 */
Yun Park8f289c82016-10-18 16:38:21 -07005181 if (adapter->ipa_context) {
5182 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005183 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005184 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005185
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005186 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5187 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005188 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005189 hdd_err("%s: Evt: %d, Interface setup failed",
5190 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005191 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005192 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005193
Yun Park8f289c82016-10-18 16:38:21 -07005194 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5195 qdf_mutex_release(&hdd_ipa->event_lock);
5196 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005197 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005198 qdf_mutex_acquire(&hdd_ipa->event_lock);
5199 }
5200
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005201 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005202 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005203 (adapter->ipa_context))->iface_id;
5204
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305205 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005206 break;
5207
5208 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305209 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005210
5211 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005212 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005213 hdd_err("%s: Evt: %d, STA already disconnected",
5214 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005215 return -EINVAL;
5216 }
Yun Parka37592b2016-06-11 17:10:28 -07005217
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005218 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005219
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005220 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005221 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005222 msg_ex->name);
5223 } else {
5224 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Park3b7152b2017-08-25 08:33:37 -07005225 if ((1 == hdd_ipa->num_iface) &&
Yun Parka37592b2016-06-11 17:10:28 -07005226 (HDD_IPA_UC_NUM_WDI_PIPE ==
Yun Park3b7152b2017-08-25 08:33:37 -07005227 hdd_ipa->activated_fw_pipe) &&
5228 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005229 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005230 }
5231
Yun Park74127cf2016-09-18 11:22:41 -07005232 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5233 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005234 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005235 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005236 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005237 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005238 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5239 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005240 }
5241
Yun Park8f289c82016-10-18 16:38:21 -07005242 hdd_ipa_cleanup_iface(adapter->ipa_context);
5243
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305244 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005245
Yun Park199c2ed2017-10-02 11:24:22 -07005246 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005247 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005248 break;
5249
5250 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005251 qdf_mutex_acquire(&hdd_ipa->event_lock);
5252
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005253 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005254 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005255 hdd_err("%s: Evt: %d, SAP already disconnected",
5256 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005257 return -EINVAL;
5258 }
5259
Yun Park3b7152b2017-08-25 08:33:37 -07005260 if ((1 == hdd_ipa->num_iface) &&
5261 (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
5262 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005263 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005264 /*
5265 * We disable WDI pipes directly here since
5266 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5267 * processed when unloading WLAN driver is in
5268 * progress
5269 */
5270 hdd_ipa_uc_disable_pipes(hdd_ipa);
5271 } else {
Yun Park199c2ed2017-10-02 11:24:22 -07005272 /*
5273 * This shouldn't happen :
5274 * No interface left but WDI pipes are still
5275 * active - force close WDI pipes
5276 */
5277 WARN_ON(1);
5278 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
5279 "No interface left but WDI pipes are still active - force close WDI pipes");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005280 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5281 }
5282 }
5283
5284 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005285 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005286 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005287 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005288 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005289 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5290 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005291 }
Yun Parka37592b2016-06-11 17:10:28 -07005292
Yun Park8f289c82016-10-18 16:38:21 -07005293 hdd_ipa_cleanup_iface(adapter->ipa_context);
5294
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305295 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005296 break;
5297
5298 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005299 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005300 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005301 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305302 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005303 return 0;
5304 }
5305
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305306 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005307 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5308 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005309 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305310 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005311 "%s: STA ID %d found, not valid",
5312 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005313 return 0;
5314 }
Yun Park312f71a2015-12-08 10:22:42 -08005315
5316 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005317 if (hdd_ipa->sap_num_connected_sta == 0 &&
5318 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005319 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005320 hdd_ipa->sta_connected) {
5321 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005322 hdd_ipa_uc_offload_enable_disable(
5323 hdd_get_adapter(hdd_ipa->hdd_ctx,
5324 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005325 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005326 qdf_mutex_acquire(&hdd_ipa->event_lock);
5327 }
Yun Parka37592b2016-06-11 17:10:28 -07005328
Yun Park312f71a2015-12-08 10:22:42 -08005329 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5330 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305331 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005332 "%s: handle 1st con ret %d",
5333 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005334
5335 if (hdd_ipa_uc_sta_is_enabled(
5336 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005337 hdd_ipa->sta_connected) {
5338 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005339 hdd_ipa_uc_offload_enable_disable(
5340 hdd_get_adapter(
5341 hdd_ipa->hdd_ctx,
5342 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005343 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005344 } else {
5345 qdf_mutex_release(&hdd_ipa->event_lock);
5346 }
Yun Parka37592b2016-06-11 17:10:28 -07005347
Yun Park312f71a2015-12-08 10:22:42 -08005348 return ret;
5349 }
5350 }
5351
5352 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005353
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305354 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005355
5356 meta.msg_type = type;
5357 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5358 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305359 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005360
5361 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305362 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005363 "msg_ex allocation failed");
5364 return -ENOMEM;
5365 }
5366 strlcpy(msg_ex->name, adapter->dev->name,
5367 IPA_RESOURCE_NAME_MAX);
5368 msg_ex->num_of_attribs = 1;
5369 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5370 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5371 msg_ex->attribs[0].offset =
5372 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5373 } else {
5374 msg_ex->attribs[0].offset =
5375 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5376 }
5377 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5378 IPA_MAC_ADDR_SIZE);
5379
5380 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5381
5382 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005383 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305384 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305385 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005386 return ret;
5387 }
5388 hdd_ipa->stats.num_send_msg++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005389
Yun Park199c2ed2017-10-02 11:24:22 -07005390 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005391 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005392 return ret;
5393
5394 case WLAN_CLIENT_DISCONNECT:
5395 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005396 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005397 "%s: IPA UC OFFLOAD NOT ENABLED",
5398 msg_ex->name);
5399 return 0;
5400 }
5401
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305402 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Park73ea8bb2017-08-25 07:27:39 -07005403 if (!hdd_ipa->sap_num_connected_sta) {
5404 qdf_mutex_release(&hdd_ipa->event_lock);
5405 hdd_err("%s: Evt: %d, Client already disconnected",
5406 msg_ex->name, meta.msg_type);
5407 return 0;
5408 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005409 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005410 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305411 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005412 "%s: STA ID %d NOT found, not valid",
5413 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005414 return 0;
5415 }
5416 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005417
Yun Park9b5030f2016-11-08 12:02:37 -08005418 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005419 if (!hdd_ipa->sap_num_connected_sta &&
5420 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005421 if ((false == hdd_ipa->resource_unloading)
5422 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305423 hdd_ipa->activated_fw_pipe) &&
5424 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005425 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5426 }
5427
Yun Park9b5030f2016-11-08 12:02:37 -08005428 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jiad9d472c92017-07-28 14:05:31 +08005429 hdd_ipa->sta_connected) {
5430 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005431 hdd_ipa_uc_offload_enable_disable(
5432 hdd_get_adapter(hdd_ipa->hdd_ctx,
5433 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005434 SIR_STA_RX_DATA_OFFLOAD, false);
jiad9d472c92017-07-28 14:05:31 +08005435 } else {
5436 qdf_mutex_release(&hdd_ipa->event_lock);
5437 }
Yun Park8f289c82016-10-18 16:38:21 -07005438 } else {
5439 qdf_mutex_release(&hdd_ipa->event_lock);
5440 }
Yun Parkfec73dc2017-09-06 10:40:07 -07005441
Yun Park199c2ed2017-10-02 11:24:22 -07005442 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005443 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005444 break;
5445
5446 default:
5447 return 0;
5448 }
5449
5450 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305451 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005452 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305453 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005454 return -ENOMEM;
5455 }
5456
5457 meta.msg_type = type;
5458 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5459 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5460
Srinivas Girigowda97852372017-03-06 16:52:59 -08005461 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005462 msg->name, meta.msg_type);
5463
5464 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5465
5466 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005467 hdd_err("%s: Evt: %d fail:%d",
5468 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305469 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005470 return ret;
5471 }
5472
5473 hdd_ipa->stats.num_send_msg++;
5474
5475end:
5476 return ret;
5477}
5478
5479/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005480 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005481 * @adapter: adapter upon which the event was received
5482 * @sta_id: station id for the event
5483 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5484 * @mac_address: MAC address associated with the event
5485 *
5486 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5487 *
5488 * Return: 0 on success, negative errno value on error
5489 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005490int hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005491 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5492{
5493 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005494 int ret = 0;
5495
5496 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005497
Leo Changa202b522016-10-14 16:13:50 -07005498 /* Data path offload only support for STA and SAP mode */
5499 if ((QDF_STA_MODE == adapter->device_mode) ||
5500 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005501 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005502
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005503 cds_ssr_unprotect(__func__);
5504
5505 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005506}
5507
5508/**
5509 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5510 * @hdd_ipa: Global HDD IPA context
5511 *
5512 * Return: None
5513 */
5514static void
5515hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5516{
5517 unsigned int pending_event_count;
5518 struct ipa_uc_pending_event *pending_event = NULL;
5519
5520 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005521 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005522 "%s, Pending Event Count %d", __func__, pending_event_count);
5523 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005524 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005525 "%s, No Pending Event", __func__);
5526 return;
5527 }
5528
5529 qdf_list_remove_front(&hdd_ipa->pending_event,
5530 (qdf_list_node_t **)&pending_event);
5531 while (pending_event != NULL) {
5532 __hdd_ipa_wlan_evt(pending_event->adapter,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005533 pending_event->sta_id,
Will Huang0ca39e22017-10-24 14:32:57 +08005534 pending_event->type,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005535 pending_event->mac_addr);
5536 qdf_mem_free(pending_event);
5537 pending_event = NULL;
5538 qdf_list_remove_front(&hdd_ipa->pending_event,
5539 (qdf_list_node_t **)&pending_event);
5540 }
5541}
5542
5543/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005544 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5545 * @state: IPA RM state value
5546 *
5547 * Return: ASCII string representing the IPA RM state
5548 */
5549static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5550{
5551 switch (state) {
5552 case HDD_IPA_RM_RELEASED:
5553 return "RELEASED";
5554 case HDD_IPA_RM_GRANT_PENDING:
5555 return "GRANT_PENDING";
5556 case HDD_IPA_RM_GRANTED:
5557 return "GRANTED";
5558 }
5559
5560 return "UNKNOWN";
5561}
5562
5563/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005564 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005565 * @hdd_ctx: HDD global context
5566 *
5567 * Allocate hdd_ipa resources, ipa pipe resource and register
5568 * wlan interface with IPA module.
5569 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305570 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005571 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005572static QDF_STATUS __hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005573{
5574 struct hdd_ipa_priv *hdd_ipa = NULL;
5575 int ret, i;
5576 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005577 struct ol_txrx_pdev_t *pdev = NULL;
Yun Park66f24c42017-03-20 10:39:47 -07005578 struct ipa_rm_perf_profile profile;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005579
5580 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305581 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005582
Yun Park199c2ed2017-10-02 11:24:22 -07005583 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
5584
Yun Parkbaa62862017-01-18 13:43:34 -08005585 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005586 if (!pdev) {
5587 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5588 goto fail_return;
5589 }
5590
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305591 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005592 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305593 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005594 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005595 }
5596
5597 hdd_ctx->hdd_ipa = hdd_ipa;
5598 ghdd_ipa = hdd_ipa;
5599 hdd_ipa->hdd_ctx = hdd_ctx;
5600 hdd_ipa->num_iface = 0;
5601
5602 /* Create the interface context */
5603 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5604 iface_context = &hdd_ipa->iface_context[i];
5605 iface_context->hdd_ipa = hdd_ipa;
5606 iface_context->cons_client =
5607 hdd_ipa_adapter_2_client[i].cons_client;
5608 iface_context->prod_client =
5609 hdd_ipa_adapter_2_client[i].prod_client;
5610 iface_context->iface_id = i;
5611 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305612 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005613 }
5614 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005615 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5616 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005617 }
5618
Leo Chang69c39692016-10-12 20:11:12 -07005619 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305620 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07005621 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305622 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005623 qdf_list_create(&hdd_ipa->pending_event, 1000);
5624 qdf_mutex_create(&hdd_ipa->event_lock);
5625 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005626
5627 ret = hdd_ipa_setup_rm(hdd_ipa);
5628 if (ret)
5629 goto fail_setup_rm;
5630
5631 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5632 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305633 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005634 hdd_ipa->sap_num_connected_sta = 0;
5635 hdd_ipa->ipa_tx_packets_diff = 0;
5636 hdd_ipa->ipa_rx_packets_diff = 0;
5637 hdd_ipa->ipa_p_tx_packets = 0;
5638 hdd_ipa->ipa_p_rx_packets = 0;
5639 hdd_ipa->resource_loading = false;
5640 hdd_ipa->resource_unloading = false;
5641 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005642 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08005643 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005644 /* Setup IPA sys_pipe for MCC */
5645 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5646 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5647 if (ret)
5648 goto fail_create_sys_pipe;
5649 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005650 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5651 goto fail_create_sys_pipe;
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005652
5653 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5654 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
5655 hdd_ipa_uc_fw_op_event_handler);
5656 hdd_ipa->uc_op_work[i].msg = NULL;
5657 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005658 } else {
5659 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5660 if (ret)
5661 goto fail_create_sys_pipe;
5662 }
5663
Yun Park66f24c42017-03-20 10:39:47 -07005664 /* When IPA clock scaling is disabled, initialze maximum clock */
5665 if (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)) {
5666 profile.max_supported_bandwidth_mbps = 800;
5667 hdd_debug("IPA clock scaling is disabled.");
5668 hdd_debug("Set initial CONS/PROD perf: %d",
5669 profile.max_supported_bandwidth_mbps);
5670 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
5671 &profile);
5672 if (ret) {
5673 hdd_err("RM CONS set perf profile failed: %d", ret);
5674 goto fail_create_sys_pipe;
5675 }
5676
5677 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
5678 &profile);
5679 if (ret) {
5680 hdd_err("RM PROD set perf profile failed: %d", ret);
5681 goto fail_create_sys_pipe;
5682 }
5683 }
5684
Yun Park777d7242017-03-30 15:38:33 -07005685 init_completion(&hdd_ipa->ipa_resource_comp);
5686
Yun Park199c2ed2017-10-02 11:24:22 -07005687 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305688 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005689
5690fail_create_sys_pipe:
5691 hdd_ipa_destroy_rm_resource(hdd_ipa);
5692fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305693 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305694 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005695 hdd_ctx->hdd_ipa = NULL;
5696 ghdd_ipa = NULL;
5697fail_return:
Yun Park199c2ed2017-10-02 11:24:22 -07005698 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: fail");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305699 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005700}
5701
5702/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005703 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5704 * @hdd_ctx: HDD global context
5705 *
5706 * Allocate hdd_ipa resources, ipa pipe resource and register
5707 * wlan interface with IPA module.
5708 *
5709 * Return: QDF_STATUS enumeration
5710 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005711QDF_STATUS hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005712{
5713 QDF_STATUS ret;
5714
5715 cds_ssr_protect(__func__);
5716 ret = __hdd_ipa_init(hdd_ctx);
5717 cds_ssr_unprotect(__func__);
5718
5719 return ret;
5720}
5721
Arun Khandavallicc544b32017-01-30 19:52:16 +05305722
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005723/**
Govind Singh1dab23b2017-08-12 13:31:00 +05305724 * __hdd_ipa_flush - flush IPA exception path SKB's
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005725 * @hdd_ctx: HDD global context
5726 *
Govind Singh1dab23b2017-08-12 13:31:00 +05305727 * Return: none
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005728 */
Govind Singh1dab23b2017-08-12 13:31:00 +05305729static void __hdd_ipa_flush(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005730{
5731 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305732 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005733 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5734
5735 if (!hdd_ipa_is_enabled(hdd_ctx))
Govind Singh1dab23b2017-08-12 13:31:00 +05305736 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005737
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005738 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005739
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305740 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005741
Nirav Shahcbc6d722016-03-01 16:24:53 +05305742 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5743 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305744 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005745
5746 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07005747 if (pm_tx_cb->ipa_tx_desc)
5748 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005749
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305750 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005751 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305752 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Govind Singh1dab23b2017-08-12 13:31:00 +05305753}
5754
5755/**
5756 * __hdd_ipa_cleanup - IPA cleanup function
5757 * @hdd_ctx: HDD global context
5758 *
5759 * Return: QDF_STATUS enumeration
5760 */
5761static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
5762{
5763 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5764 int i;
5765 struct hdd_ipa_iface_context *iface_context = NULL;
5766
5767 if (!hdd_ipa_is_enabled(hdd_ctx))
5768 return QDF_STATUS_SUCCESS;
5769
5770 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5771 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5772 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5773 }
5774
5775 /* Teardown IPA sys_pipe for MCC */
5776 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5777 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5778
5779 hdd_ipa_destroy_rm_resource(hdd_ipa);
5780
5781 __hdd_ipa_flush(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005782
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305783 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07005784 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005785
5786 /* destory the interface lock */
5787 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5788 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305789 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005790 }
5791
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005792 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08005793 if (ipa_uc_dereg_rdyCB())
5794 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5795 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005796 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305797 qdf_mutex_destroy(&hdd_ipa->event_lock);
5798 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07005799 qdf_list_destroy(&hdd_ipa->pending_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005800
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005801 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5802 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5803 hdd_ipa->uc_op_work[i].msg = NULL;
5804 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005805 }
5806
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305807 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005808 hdd_ctx->hdd_ipa = NULL;
5809
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305810 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005811}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005812
5813/**
Govind Singh1dab23b2017-08-12 13:31:00 +05305814 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_flush
5815 * @hdd_ctx: HDD global context
5816 *
5817 * Return: None
5818 */
5819void hdd_ipa_flush(struct hdd_context *hdd_ctx)
5820{
5821 cds_ssr_protect(__func__);
5822 __hdd_ipa_flush(hdd_ctx);
5823 cds_ssr_unprotect(__func__);
5824}
5825
5826/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005827 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5828 * @hdd_ctx: HDD global context
5829 *
5830 * Return: QDF_STATUS enumeration
5831 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005832QDF_STATUS hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005833{
5834 QDF_STATUS ret;
5835
5836 cds_ssr_protect(__func__);
5837 ret = __hdd_ipa_cleanup(hdd_ctx);
5838 cds_ssr_unprotect(__func__);
5839
5840 return ret;
5841}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005842#endif /* IPA_OFFLOAD */