blob: 9f49fcc610656a000b250dc02a2f78a4c58ba8d0 [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 */
Yun Parkb4f591d2017-03-29 15:51:01 -070038#include <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;
215 hdd_adapter_t *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;
243 hdd_adapter_t *adapter;
244 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;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800330 hdd_adapter_t *adapter;
331 enum ipa_wlan_event type;
332 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530333 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800334};
335
336/**
337 * struct uc_rm_work_struct
338 * @work: uC RM work
339 * @event: IPA RM event
340 */
341struct uc_rm_work_struct {
342 struct work_struct work;
343 enum ipa_rm_event event;
344};
345
346/**
347 * struct uc_op_work_struct
348 * @work: uC OP work
349 * @msg: OP message
350 */
351struct uc_op_work_struct {
352 struct work_struct work;
353 struct op_msg_type *msg;
354};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800355
356/**
357 * struct uc_rt_debug_info
358 * @time: system time
359 * @ipa_excep_count: IPA exception packet count
360 * @rx_drop_count: IPA Rx drop packet count
361 * @net_sent_count: IPA Rx packet sent to network stack count
362 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800363 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800364 * @tx_fwd_count: IPA Tx forward packet count
365 * @rx_destructor_call: IPA Rx packet destructor count
366 */
367struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530368 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800369 uint64_t ipa_excep_count;
370 uint64_t rx_drop_count;
371 uint64_t net_sent_count;
372 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800373 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800374 uint64_t tx_fwd_count;
375 uint64_t rx_destructor_call;
376};
377
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;
jiad14fe4fb2017-08-08 13:33:14 +0800442 uint16_t tx_desc_size;
Yun Park52b2b992016-09-22 15:49:51 -0700443 struct hdd_ipa_tx_desc *tx_desc_list;
444 struct list_head free_tx_desc_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800445
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700446 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800447
448 struct dentry *debugfs_dir;
449 struct hdd_ipa_stats stats;
450
451 struct notifier_block ipv4_notifier;
452 uint32_t curr_prod_bw;
453 uint32_t curr_cons_bw;
454
455 uint8_t activated_fw_pipe;
456 uint8_t sap_num_connected_sta;
457 uint8_t sta_connected;
458 uint32_t tx_pipe_handle;
459 uint32_t rx_pipe_handle;
460 bool resource_loading;
461 bool resource_unloading;
462 bool pending_cons_req;
463 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530464 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530465 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700466 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800467 uint32_t ipa_tx_packets_diff;
468 uint32_t ipa_rx_packets_diff;
469 uint32_t ipa_p_tx_packets;
470 uint32_t ipa_p_rx_packets;
471 uint32_t stat_req_reason;
472 uint64_t ipa_tx_forward;
473 uint64_t ipa_rx_discard;
474 uint64_t ipa_rx_net_send_count;
475 uint64_t ipa_rx_internel_drop_count;
476 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530477 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800478 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
479 unsigned int rt_buf_fill_index;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800480 struct ipa_wdi_in_params cons_pipe_in;
481 struct ipa_wdi_in_params prod_pipe_in;
482 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800483 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530484 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530485 qdf_mutex_t rt_debug_lock;
486 qdf_mutex_t ipa_lock;
Yun Parkb4f591d2017-03-29 15:51:01 -0700487
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800488 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
489 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Yun Park637d6482016-10-05 10:51:33 -0700490#ifdef FEATURE_METERING
491 struct ipa_uc_sharing_stats ipa_sharing_stats;
492 struct ipa_uc_quota_rsp ipa_quota_rsp;
493 struct ipa_uc_quota_ind ipa_quota_ind;
494 struct completion ipa_uc_sharing_stats_comp;
495 struct completion ipa_uc_set_quota_comp;
496#endif
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) \
Srinivas Girigowda576b2352017-08-25 14:44:26 -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) \
Srinivas Girigowda576b2352017-08-25 14:44:26 -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 Parkb187d542016-11-14 18:10:04 -0800542#define HDD_IPA_DBG_DUMP_RX_LEN 32
543#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
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800563static struct hdd_ipa_priv *ghdd_ipa;
564
565/* Local Function Prototypes */
566static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
567 unsigned long data);
568static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
569 unsigned long data);
Yun Parkb4f591d2017-03-29 15:51:01 -0700570#ifdef FEATURE_METERING
571static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
572 void *data);
573#else
574static void hdd_ipa_wdi_meter_notifier_cb(void);
575#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800576static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800577
578static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700579static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800580
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800581#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
582 defined(IPA_CLIENT_IS_MHI_CONS))
583/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800584 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
585 * @priv_ctxt: hdd ipa local context
586 *
587 * Will be called by IPA context.
588 * It's atomic context, then should be scheduled to kworker thread
589 *
590 * Return: None
591 */
592static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
593{
594 struct hdd_ipa_priv *hdd_ipa;
595 struct op_msg_type *msg;
596 struct uc_op_work_struct *uc_op_work;
597
598 if (priv_ctxt == NULL) {
599 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
600 return;
601 }
602
603 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
604 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
605 if (!msg) {
606 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
607 return;
608 }
609
610 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
611
612 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
613
614 /* When the same uC OPCODE is already pended, just return */
615 if (uc_op_work->msg)
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530616 goto done;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800617
618 uc_op_work->msg = msg;
619 schedule_work(&uc_op_work->work);
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530620
jiadd91a6842017-08-01 14:46:02 +0800621 /* work handler will free the msg buffer */
622 return;
623
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530624done:
625 qdf_mem_free(msg);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800626}
627
628/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800629 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
630 * @ctrl: WDI control value
631 *
632 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
633 *
634 * Return: 0 on message send to ipa, -1 on failure
635 */
636static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
637{
638 struct ipa_msg_meta meta;
639 struct ipa_wlan_msg *ipa_msg;
640 int ret = 0;
641
642 /* WDI enable message to IPA */
643 meta.msg_len = sizeof(*ipa_msg);
644 ipa_msg = qdf_mem_malloc(meta.msg_len);
645 if (ipa_msg == NULL) {
646 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
647 "msg allocation failed");
648 return -ENOMEM;
649 }
650
651 if (ctrl == true)
652 meta.msg_type = WLAN_WDI_ENABLE;
653 else
654 meta.msg_type = WLAN_WDI_DISABLE;
655
Srinivas Girigowda97852372017-03-06 16:52:59 -0800656 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800657 "ipa_send_msg(Evt:%d)", meta.msg_type);
658 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
659 if (ret) {
660 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
661 "ipa_send_msg(Evt:%d)-fail=%d",
662 meta.msg_type, ret);
663 qdf_mem_free(ipa_msg);
664 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800665 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800666}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800667
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800668/**
669 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
670 * @hdd_ipa: HDD IPA local context
671 *
672 * Register IPA UC ready callback function to IPA kernel driver
673 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
674 * open WDI pipe after WLAN driver loading finished
675 *
676 * Return: 0 Success
677 * -EPERM Registration fail
678 */
679static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
680{
681 struct ipa_wdi_uc_ready_params uc_ready_param;
682 int ret = 0;
683
684 hdd_ipa->uc_loaded = false;
685 uc_ready_param.priv = (void *)hdd_ipa;
686 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
687 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
688 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
689 "UC Ready CB register fail");
690 return -EPERM;
691 }
692 if (true == uc_ready_param.is_uC_ready) {
Srinivas Girigowda2b5d47c2017-03-29 00:28:46 -0700693 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800694 hdd_ipa->uc_loaded = true;
695 } else {
696 ret = hdd_ipa_uc_send_wdi_control_msg(false);
697 }
698
699 return ret;
700}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800701#else
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800702static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
703{
704 hdd_ipa->uc_loaded = true;
705 return 0;
706}
707
708static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
709{
710 return 0;
711}
712#endif
713
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800714/**
715 * hdd_ipa_is_enabled() - Is IPA enabled?
716 * @hdd_ctx: Global HDD context
717 *
718 * Return: true if IPA is enabled, false otherwise
719 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700720bool hdd_ipa_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800721{
722 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
723}
724
725/**
726 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
727 * @hdd_ctx: Global HDD context
728 *
729 * Return: true if IPA uC offload is enabled, false otherwise
730 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700731bool hdd_ipa_uc_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732{
733 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
734}
735
736/**
737 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
738 * @hdd_ctx: Global HDD context
739 *
740 * Return: true if STA mode IPA uC offload is enabled, false otherwise
741 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700742static inline bool hdd_ipa_uc_sta_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800743{
744 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
745}
746
747/**
Guolei Bianca144d82016-11-10 11:07:42 +0800748 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
749 * @hdd_ipa: Global HDD IPA context
750 *
751 * Return: None
752 */
Guolei Bianca144d82016-11-10 11:07:42 +0800753static inline void hdd_ipa_uc_sta_reset_sta_connected(
754 struct hdd_ipa_priv *hdd_ipa)
755{
Yun Park637d6482016-10-05 10:51:33 -0700756 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800757 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700758 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800759}
Guolei Bianca144d82016-11-10 11:07:42 +0800760
761/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800762 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
763 * @hdd_ipa: Global HDD IPA context
764 *
765 * Return: true if pre-filter is enabled, otherwise false
766 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700767static inline bool hdd_ipa_is_pre_filter_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800768{
769 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
770 HDD_IPA_PRE_FILTER_ENABLE_MASK);
771}
772
773/**
774 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
775 * @hdd_ipa: Global HDD IPA context
776 *
777 * Return: true if IPv6 is enabled, otherwise false
778 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700779static inline bool hdd_ipa_is_ipv6_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800780{
781 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
782}
783
784/**
785 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
786 * @hdd_ipa: Global HDD IPA context
787 *
788 * Return: true if resource manager is enabled, otherwise false
789 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700790static inline bool hdd_ipa_is_rm_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800791{
792 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
793}
794
795/**
796 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
797 * @hdd_ipa: Global HDD IPA context
798 *
799 * Return: true if resource manager is enabled, otherwise false
800 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700801static inline bool hdd_ipa_is_rt_debugging_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800802{
803 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
804}
805
806/**
807 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
808 * @hdd_ipa: Global HDD IPA context
809 *
810 * Return: true if clock scaling is enabled, otherwise false
811 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700812static inline bool hdd_ipa_is_clk_scaling_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813{
814 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
815 HDD_IPA_CLK_SCALING_ENABLE_MASK |
816 HDD_IPA_RM_ENABLE_MASK);
817}
818
819/**
820 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
821 * @ctext: pointer to hdd context.
822 *
823 * If rt debug enabled, periodically called, and fill debug buffer
824 *
825 * Return: none
826 */
827static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
828{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700829 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800830 struct hdd_ipa_priv *hdd_ipa;
831 struct uc_rt_debug_info *dump_info = NULL;
832
833 if (wlan_hdd_validate_context(hdd_ctx))
834 return;
835
836 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700837 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800838 return;
839 }
840
841 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
842
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530843 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800844 dump_info = &hdd_ipa->rt_bug_buffer[
845 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
846
Deepthi Gowri6acee342016-10-28 15:00:38 +0530847 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800848 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
849 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
850 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800851 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800852 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
853 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
855 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530856 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800857
Anurag Chouhan210db072016-02-22 18:42:15 +0530858 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
860}
861
862/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700863 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800864 * @hdd_ctx: pointer to hdd context.
865 *
866 * If rt debug enabled, dump debug buffer contents based on requirement
867 *
868 * Return: none
869 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700870static void __hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800871{
872 struct hdd_ipa_priv *hdd_ipa;
873 unsigned int dump_count;
874 unsigned int dump_index;
875 struct uc_rt_debug_info *dump_info = NULL;
876
877 if (wlan_hdd_validate_context(hdd_ctx))
878 return;
879
880 hdd_ipa = hdd_ctx->hdd_ipa;
881 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700882 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800883 return;
884 }
885
Chris Guo1751acf2017-07-03 14:09:01 +0800886 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
887 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
888 "%s: IPA RT debug is not enabled", __func__);
889 return;
890 }
891
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530892 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800893 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530894 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800895 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530897 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898 for (dump_count = 0;
899 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
900 dump_count++) {
901 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
902 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
903 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530904 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530905 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800906 dump_info->time, dump_info->ipa_excep_count,
907 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800908 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800909 dump_info->rx_destructor_call,
910 dump_info->rx_discard_count);
911 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530912 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530913 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800914 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
915}
916
917/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700918 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
919 * __hdd_ipa_uc_rt_debug_host_dump
920 * @hdd_ctx: pointer to hdd context.
921 *
922 * If rt debug enabled, dump debug buffer contents based on requirement
923 *
924 * Return: none
925 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700926void hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700927{
928 cds_ssr_protect(__func__);
929 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
930 cds_ssr_unprotect(__func__);
931}
932
933/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
935 * @ctext: pointer to hdd context.
936 *
937 * periodically called by timer expire
938 * will try to alloc dummy memory and detect out of memory condition
939 * if out of memory detected, dump wlan-ipa stats
940 *
941 * Return: none
942 */
943static void hdd_ipa_uc_rt_debug_handler(void *ctext)
944{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700945 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700946 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800947 void *dummy_ptr = NULL;
948
949 if (wlan_hdd_validate_context(hdd_ctx))
950 return;
951
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700952 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
953
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800954 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700955 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
956 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800957 return;
958 }
959
960 /* Allocate dummy buffer periodically and free immediately. this will
961 * proactively detect OOM and if allocation fails dump ipa stats
962 */
963 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
964 GFP_KERNEL | GFP_ATOMIC);
965 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800966 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
967 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -0700968 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
969 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800970 } else {
971 kfree(dummy_ptr);
972 }
973
Anurag Chouhan210db072016-02-22 18:42:15 +0530974 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800975 HDD_IPA_UC_RT_DEBUG_PERIOD);
976}
977
978/**
Yun Parkb187d542016-11-14 18:10:04 -0800979 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800980 * @skb: packet pinter
981 *
982 * when free data packet, will be invoked by wlan client and will increase
983 * free counter
984 *
985 * Return: none
986 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700987static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800988{
989 if (!ghdd_ipa) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700990 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "invalid hdd context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800991 return;
992 }
993
994 ghdd_ipa->ipa_rx_destructor_count++;
995}
996
997/**
Yun Parkb187d542016-11-14 18:10:04 -0800998 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800999 * @hdd_ctx: hdd main context
1000 *
1001 * free all rt debugging resources
1002 *
1003 * Return: none
1004 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001005static void hdd_ipa_uc_rt_debug_deinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001007 struct hdd_ipa_priv *hdd_ipa;
1008
1009 if (wlan_hdd_validate_context(hdd_ctx))
1010 return;
1011
1012 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001013
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301014 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001015
1016 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001017 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1018 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019 return;
1020 }
1021
Anurag Chouhan210db072016-02-22 18:42:15 +05301022 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001023 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1024 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1025 }
1026 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1027
1028 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301029 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1030 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001031 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301032 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001033}
1034
1035/**
Yun Parkb187d542016-11-14 18:10:04 -08001036 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001037 * @hdd_ctx: hdd main context
1038 *
1039 * alloc and initialize all rt debugging resources
1040 *
1041 * Return: none
1042 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001043static void hdd_ipa_uc_rt_debug_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001045 struct hdd_ipa_priv *hdd_ipa;
1046
Chris Guo1751acf2017-07-03 14:09:01 +08001047 if (wlan_hdd_validate_context_in_loading(hdd_ctx))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001048 return;
1049
1050 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001051
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301052 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001053 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301054 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001055 sizeof(struct uc_rt_debug_info) *
1056 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1057 hdd_ipa->ipa_tx_forward = 0;
1058 hdd_ipa->ipa_rx_discard = 0;
1059 hdd_ipa->ipa_rx_net_send_count = 0;
1060 hdd_ipa->ipa_rx_internel_drop_count = 0;
1061 hdd_ipa->ipa_rx_destructor_count = 0;
1062
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001063 /* Reatime debug enable on feature enable */
1064 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001065 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1066 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001067 return;
1068 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001069
1070 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1071 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1072 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1073 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1074
Anurag Chouhan210db072016-02-22 18:42:15 +05301075 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301077 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001078 HDD_IPA_UC_RT_DEBUG_PERIOD);
1079
1080}
1081
1082/**
Yun Parkb187d542016-11-14 18:10:04 -08001083 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1084 * @hdd_ipa: HDD IPA struct
1085 *
1086 * Dump entries in struct hdd_ipa
1087 *
1088 * Return: none
1089 */
1090static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1091{
1092 int i;
1093
1094 /* HDD IPA */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001095 hdd_info("==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001096 "num_iface: %d\n"
1097 "rm_state: %d\n"
1098 "rm_lock: %p\n"
1099 "uc_rm_work: %p\n"
1100 "uc_op_work: %p\n"
1101 "wake_lock: %p\n"
1102 "wake_lock_work: %p\n"
1103 "wake_lock_released: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001104 "tx_ref_cnt: %d\n"
1105 "pm_queue_head----\n"
1106 "\thead: %p\n"
1107 "\ttail: %p\n"
1108 "\tqlen: %d\n"
1109 "pm_work: %p\n"
1110 "pm_lock: %p\n"
1111 "suspended: %d\n",
1112 hdd_ipa->num_iface,
1113 hdd_ipa->rm_state,
1114 &hdd_ipa->rm_lock,
1115 &hdd_ipa->uc_rm_work,
1116 &hdd_ipa->uc_op_work,
1117 &hdd_ipa->wake_lock,
1118 &hdd_ipa->wake_lock_work,
1119 hdd_ipa->wake_lock_released,
Yun Parkb187d542016-11-14 18:10:04 -08001120 hdd_ipa->tx_ref_cnt.counter,
1121 hdd_ipa->pm_queue_head.head,
1122 hdd_ipa->pm_queue_head.tail,
1123 hdd_ipa->pm_queue_head.qlen,
1124 &hdd_ipa->pm_work,
1125 &hdd_ipa->pm_lock,
1126 hdd_ipa->suspended);
Yun Park52b2b992016-09-22 15:49:51 -07001127 hdd_err("\nq_lock: %p\n"
Yun Parkb187d542016-11-14 18:10:04 -08001128 "pend_desc_head----\n"
1129 "\tnext: %p\n"
1130 "\tprev: %p\n"
1131 "hdd_ctx: %p\n"
1132 "debugfs_dir: %p\n"
1133 "stats: %p\n"
1134 "ipv4_notifier: %p\n"
1135 "curr_prod_bw: %d\n"
1136 "curr_cons_bw: %d\n"
1137 "activated_fw_pipe: %d\n"
1138 "sap_num_connected_sta: %d\n"
1139 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001140 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001141 hdd_ipa->pend_desc_head.next,
1142 hdd_ipa->pend_desc_head.prev,
1143 hdd_ipa->hdd_ctx,
1144 hdd_ipa->debugfs_dir,
1145 &hdd_ipa->stats,
1146 &hdd_ipa->ipv4_notifier,
1147 hdd_ipa->curr_prod_bw,
1148 hdd_ipa->curr_cons_bw,
1149 hdd_ipa->activated_fw_pipe,
1150 hdd_ipa->sap_num_connected_sta,
1151 (unsigned int)hdd_ipa->sta_connected
1152 );
Srinivas Girigowda97852372017-03-06 16:52:59 -08001153 hdd_info("\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001154 "rx_pipe_handle: 0x%x\n"
1155 "resource_loading: %d\n"
1156 "resource_unloading: %d\n"
1157 "pending_cons_req: %d\n"
1158 "pending_event----\n"
1159 "\tanchor.next: %p\n"
1160 "\tanchor.prev: %p\n"
1161 "\tcount: %d\n"
1162 "\tmax_size: %d\n"
1163 "event_lock: %p\n"
1164 "ipa_tx_packets_diff: %d\n"
1165 "ipa_rx_packets_diff: %d\n"
1166 "ipa_p_tx_packets: %d\n"
1167 "ipa_p_rx_packets: %d\n"
1168 "stat_req_reason: %d\n",
1169 hdd_ipa->tx_pipe_handle,
1170 hdd_ipa->rx_pipe_handle,
1171 hdd_ipa->resource_loading,
1172 hdd_ipa->resource_unloading,
1173 hdd_ipa->pending_cons_req,
1174 hdd_ipa->pending_event.anchor.next,
1175 hdd_ipa->pending_event.anchor.prev,
1176 hdd_ipa->pending_event.count,
1177 hdd_ipa->pending_event.max_size,
1178 &hdd_ipa->event_lock,
1179 hdd_ipa->ipa_tx_packets_diff,
1180 hdd_ipa->ipa_rx_packets_diff,
1181 hdd_ipa->ipa_p_tx_packets,
1182 hdd_ipa->ipa_p_rx_packets,
1183 hdd_ipa->stat_req_reason);
1184
Srinivas Girigowda97852372017-03-06 16:52:59 -08001185 hdd_info("assoc_stas_map([id]is_reserved/sta_id): ");
Yun Parkb187d542016-11-14 18:10:04 -08001186 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001187 hdd_info(" [%d]%d/%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001188 hdd_ipa->assoc_stas_map[i].is_reserved,
1189 hdd_ipa->assoc_stas_map[i].sta_id);
1190 }
1191}
1192
1193/**
1194 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1195 * @hdd_ipa: HDD IPA struct
1196 *
1197 * Dump entire struct hdd_ipa_sys_pipe
1198 *
1199 * Return: none
1200 */
1201static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1202{
1203 int i;
1204
1205 /* IPA SYS Pipes */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001206 hdd_info("==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001207
1208 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1209 struct hdd_ipa_sys_pipe *sys_pipe;
1210 struct ipa_sys_connect_params *ipa_sys_params;
1211
1212 sys_pipe = &hdd_ipa->sys_pipe[i];
1213 ipa_sys_params = &sys_pipe->ipa_sys_params;
1214
Srinivas Girigowda97852372017-03-06 16:52:59 -08001215 hdd_info("sys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001216 "\tconn_hdl: 0x%x\n"
1217 "\tconn_hdl_valid: %d\n"
1218 "\tnat_en: %d\n"
1219 "\thdr_len %d\n"
1220 "\thdr_additional_const_len: %d\n"
1221 "\thdr_ofst_pkt_size_valid: %d\n"
1222 "\thdr_ofst_pkt_size: %d\n"
1223 "\thdr_little_endian: %d\n"
1224 "\tmode: %d\n"
1225 "\tclient: %d\n"
1226 "\tdesc_fifo_sz: %d\n"
1227 "\tpriv: %p\n"
1228 "\tnotify: %p\n"
1229 "\tskip_ep_cfg: %d\n"
1230 "\tkeep_ipa_awake: %d\n",
1231 i,
1232 sys_pipe->conn_hdl,
1233 sys_pipe->conn_hdl_valid,
1234 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1235 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1236 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1237 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1238 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1239 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1240 ipa_sys_params->ipa_ep_cfg.mode.mode,
1241 ipa_sys_params->client,
1242 ipa_sys_params->desc_fifo_sz,
1243 ipa_sys_params->priv,
1244 ipa_sys_params->notify,
1245 ipa_sys_params->skip_ep_cfg,
1246 ipa_sys_params->keep_ipa_awake);
1247 }
1248}
1249
1250/**
1251 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1252 * @hdd_ipa: HDD IPA struct
1253 *
1254 * Dump entire struct hdd_ipa_iface_context
1255 *
1256 * Return: none
1257 */
1258static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1259{
1260 int i;
1261
1262 /* IPA Interface Contexts */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001263 hdd_info("==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001264
1265 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1266 struct hdd_ipa_iface_context *iface_context;
1267
1268 iface_context = &hdd_ipa->iface_context[i];
1269
Srinivas Girigowda97852372017-03-06 16:52:59 -08001270 hdd_info("iface_context[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001271 "\thdd_ipa: %p\n"
1272 "\tadapter: %p\n"
1273 "\ttl_context: %p\n"
1274 "\tcons_client: %d\n"
1275 "\tprod_client: %d\n"
1276 "\tiface_id: %d\n"
1277 "\tsta_id: %d\n"
1278 "\tinterface_lock: %p\n"
1279 "\tifa_address: 0x%x\n",
1280 i,
1281 iface_context->hdd_ipa,
1282 iface_context->adapter,
1283 iface_context->tl_context,
1284 iface_context->cons_client,
1285 iface_context->prod_client,
1286 iface_context->iface_id,
1287 iface_context->sta_id,
1288 &iface_context->interface_lock,
1289 iface_context->ifa_address);
1290 }
1291}
1292
1293/**
1294 * hdd_ipa_dump_info() - dump HDD IPA struct
1295 * @pHddCtx: hdd main context
1296 *
1297 * Dump entire struct hdd_ipa
1298 *
1299 * Return: none
1300 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001301void hdd_ipa_dump_info(struct hdd_context *hdd_ctx)
Yun Parkb187d542016-11-14 18:10:04 -08001302{
1303 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1304
1305 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1306 hdd_ipa_dump_sys_pipe(hdd_ipa);
1307 hdd_ipa_dump_iface_context(hdd_ipa);
1308}
1309
1310/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001311 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1312 * enabled
1313 *
1314 * This routine is called to set TX flow info if IPA is enabled
1315 *
1316 * Return: None
1317 */
1318void hdd_ipa_set_tx_flow_info(void)
1319{
1320 hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL;
1321 QDF_STATUS status;
1322 hdd_adapter_t *adapter;
1323 hdd_station_ctx_t *pHddStaCtx;
1324 hdd_ap_ctx_t *hdd_ap_ctx;
1325 hdd_hostapd_state_t *hostapd_state;
1326 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1327 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1328 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1329 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1330 const char *p2pMode = "DEV";
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001331 struct hdd_context *hdd_ctx;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001332 cds_context_type *cds_ctx;
1333#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1334 uint8_t targetChannel = 0;
1335 uint8_t preAdapterChannel = 0;
1336 uint8_t channel24;
1337 uint8_t channel5;
1338 hdd_adapter_t *preAdapterContext = NULL;
1339 hdd_adapter_t *adapter2_4 = NULL;
1340 hdd_adapter_t *adapter5 = NULL;
1341 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1342#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1343 struct wlan_objmgr_psoc *psoc;
1344
1345 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1346 if (!hdd_ctx) {
1347 cds_err("HDD context is NULL");
1348 return;
1349 }
1350
1351 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1352 if (!cds_ctx) {
1353 cds_err("Invalid CDS Context");
1354 return;
1355 }
1356
1357 psoc = hdd_ctx->hdd_psoc;
1358 status = hdd_get_front_adapter(hdd_ctx, &adapterNode);
1359 while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) {
1360 adapter = adapterNode->pAdapter;
1361 switch (adapter->device_mode) {
1362 case QDF_STA_MODE:
1363 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1364 if (eConnectionState_Associated ==
1365 pHddStaCtx->conn_info.connState) {
1366 staChannel =
1367 pHddStaCtx->conn_info.operationChannel;
1368 qdf_copy_macaddr(&staBssid,
1369 &pHddStaCtx->conn_info.bssId);
1370#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1371 targetChannel = staChannel;
1372#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1373 }
1374 break;
1375 case QDF_P2P_CLIENT_MODE:
1376 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1377 if (eConnectionState_Associated ==
1378 pHddStaCtx->conn_info.connState) {
1379 p2pChannel =
1380 pHddStaCtx->conn_info.operationChannel;
1381 qdf_copy_macaddr(&p2pBssid,
1382 &pHddStaCtx->conn_info.bssId);
1383 p2pMode = "CLI";
1384#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1385 targetChannel = p2pChannel;
1386#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1387 }
1388 break;
1389 case QDF_P2P_GO_MODE:
1390 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1391 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1392 if (hostapd_state->bssState == BSS_START
1393 && hostapd_state->qdf_status ==
1394 QDF_STATUS_SUCCESS) {
1395 p2pChannel = hdd_ap_ctx->operatingChannel;
1396 qdf_copy_macaddr(&p2pBssid,
1397 &adapter->macAddressCurrent);
1398#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1399 targetChannel = p2pChannel;
1400#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1401 }
1402 p2pMode = "GO";
1403 break;
1404 case QDF_SAP_MODE:
1405 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1406 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1407 if (hostapd_state->bssState == BSS_START
1408 && hostapd_state->qdf_status ==
1409 QDF_STATUS_SUCCESS) {
1410 apChannel = hdd_ap_ctx->operatingChannel;
1411 qdf_copy_macaddr(&apBssid,
1412 &adapter->macAddressCurrent);
1413#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1414 targetChannel = apChannel;
1415#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1416 }
1417 break;
1418 case QDF_IBSS_MODE:
1419 default:
1420 break;
1421 }
1422#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1423 if (targetChannel) {
1424 /*
1425 * This is first adapter detected as active
1426 * set as default for none concurrency case
1427 */
1428 if (!preAdapterChannel) {
1429 /* If IPA UC data path is enabled,
1430 * target should reserve extra tx descriptors
1431 * for IPA data path.
1432 * Then host data path should allow less TX
1433 * packet pumping in case IPA
1434 * data path enabled
1435 */
1436 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1437 (QDF_SAP_MODE == adapter->device_mode)) {
1438 adapter->tx_flow_low_watermark =
1439 hdd_ctx->config->TxFlowLowWaterMark +
1440 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1441 } else {
1442 adapter->tx_flow_low_watermark =
1443 hdd_ctx->config->
1444 TxFlowLowWaterMark;
1445 }
1446 adapter->tx_flow_high_watermark_offset =
1447 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1448 cdp_fc_ll_set_tx_pause_q_depth(soc,
1449 adapter->sessionId,
1450 hdd_ctx->config->TxFlowMaxQueueDepth);
1451 cds_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
1452 adapter->device_mode,
1453 targetChannel,
1454 adapter->tx_flow_low_watermark,
1455 adapter->tx_flow_low_watermark +
1456 adapter->tx_flow_high_watermark_offset,
1457 hdd_ctx->config->TxFlowMaxQueueDepth);
1458 preAdapterChannel = targetChannel;
1459 preAdapterContext = adapter;
1460 } else {
1461 /*
1462 * SCC, disable TX flow control for both
1463 * SCC each adapter cannot reserve dedicated
1464 * channel resource, as a result, if any adapter
1465 * blocked OS Q by flow control,
1466 * blocked adapter will lost chance to recover
1467 */
1468 if (preAdapterChannel == targetChannel) {
1469 /* Current adapter */
1470 adapter->tx_flow_low_watermark = 0;
1471 adapter->
1472 tx_flow_high_watermark_offset = 0;
1473 cdp_fc_ll_set_tx_pause_q_depth(soc,
1474 adapter->sessionId,
1475 hdd_ctx->config->
1476 TxHbwFlowMaxQueueDepth);
1477 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1478 hdd_device_mode_to_string(
1479 adapter->device_mode),
1480 adapter->device_mode,
1481 targetChannel,
1482 adapter->tx_flow_low_watermark,
1483 adapter->tx_flow_low_watermark +
1484 adapter->
1485 tx_flow_high_watermark_offset,
1486 hdd_ctx->config->
1487 TxHbwFlowMaxQueueDepth);
1488
1489 if (!preAdapterContext) {
1490 cds_err("SCC: Previous adapter context NULL");
1491 continue;
1492 }
1493
1494 /* Previous adapter */
1495 preAdapterContext->
1496 tx_flow_low_watermark = 0;
1497 preAdapterContext->
1498 tx_flow_high_watermark_offset = 0;
1499 cdp_fc_ll_set_tx_pause_q_depth(soc,
1500 preAdapterContext->sessionId,
1501 hdd_ctx->config->
1502 TxHbwFlowMaxQueueDepth);
1503 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1504 hdd_device_mode_to_string(
1505 preAdapterContext->device_mode
1506 ),
1507 preAdapterContext->device_mode,
1508 targetChannel,
1509 preAdapterContext->
1510 tx_flow_low_watermark,
1511 preAdapterContext->
1512 tx_flow_low_watermark +
1513 preAdapterContext->
1514 tx_flow_high_watermark_offset,
1515 hdd_ctx->config->
1516 TxHbwFlowMaxQueueDepth);
1517 }
1518 /*
1519 * MCC, each adapter will have dedicated
1520 * resource
1521 */
1522 else {
1523 /* current channel is 2.4 */
1524 if (targetChannel <=
1525 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1526 channel24 = targetChannel;
1527 channel5 = preAdapterChannel;
1528 adapter2_4 = adapter;
1529 adapter5 = preAdapterContext;
1530 } else {
1531 /* Current channel is 5 */
1532 channel24 = preAdapterChannel;
1533 channel5 = targetChannel;
1534 adapter2_4 = preAdapterContext;
1535 adapter5 = adapter;
1536 }
1537
1538 if (!adapter5) {
1539 cds_err("MCC: 5GHz adapter context NULL");
1540 continue;
1541 }
1542 adapter5->tx_flow_low_watermark =
1543 hdd_ctx->config->
1544 TxHbwFlowLowWaterMark;
1545 adapter5->
1546 tx_flow_high_watermark_offset =
1547 hdd_ctx->config->
1548 TxHbwFlowHighWaterMarkOffset;
1549 cdp_fc_ll_set_tx_pause_q_depth(soc,
1550 adapter5->sessionId,
1551 hdd_ctx->config->
1552 TxHbwFlowMaxQueueDepth);
1553 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1554 hdd_device_mode_to_string(
1555 adapter5->device_mode),
1556 adapter5->device_mode,
1557 channel5,
1558 adapter5->tx_flow_low_watermark,
1559 adapter5->
1560 tx_flow_low_watermark +
1561 adapter5->
1562 tx_flow_high_watermark_offset,
1563 hdd_ctx->config->
1564 TxHbwFlowMaxQueueDepth);
1565
1566 if (!adapter2_4) {
1567 cds_err("MCC: 2.4GHz adapter context NULL");
1568 continue;
1569 }
1570 adapter2_4->tx_flow_low_watermark =
1571 hdd_ctx->config->
1572 TxLbwFlowLowWaterMark;
1573 adapter2_4->
1574 tx_flow_high_watermark_offset =
1575 hdd_ctx->config->
1576 TxLbwFlowHighWaterMarkOffset;
1577 cdp_fc_ll_set_tx_pause_q_depth(soc,
1578 adapter2_4->sessionId,
1579 hdd_ctx->config->
1580 TxLbwFlowMaxQueueDepth);
1581 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1582 hdd_device_mode_to_string(
1583 adapter2_4->device_mode),
1584 adapter2_4->device_mode,
1585 channel24,
1586 adapter2_4->
1587 tx_flow_low_watermark,
1588 adapter2_4->
1589 tx_flow_low_watermark +
1590 adapter2_4->
1591 tx_flow_high_watermark_offset,
1592 hdd_ctx->config->
1593 TxLbwFlowMaxQueueDepth);
1594
1595 }
1596 }
1597 }
1598 targetChannel = 0;
1599#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1600 status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext);
1601 adapterNode = pNext;
1602 }
1603 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1604}
1605
1606/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001607 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001609 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1610 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611 *
1612 * Return: true if IPA is enabled, false otherwise
1613 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001614static void __hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001615 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1616{
1617 struct hdd_ipa_priv *hdd_ipa;
1618
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619 *ipa_tx_diff = 0;
1620 *ipa_rx_diff = 0;
1621
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001622 if (wlan_hdd_validate_context(hdd_ctx))
1623 return;
1624
1625 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1626
1627 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1628 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629 return;
1630 }
1631
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301632 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001633 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1634 (false == hdd_ipa->resource_loading)) {
1635 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1636 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001637 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638 *ipa_tx_diff, *ipa_rx_diff);
1639 }
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 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001666static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001667{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001668 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001669 struct hdd_ipa_priv *hdd_ipa;
1670
Yun Park637d6482016-10-05 10:51:33 -07001671 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001673
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001674 hdd_ctx = (struct hdd_context *)adapter->pHddCtx;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001675
1676 if (wlan_hdd_validate_context(hdd_ctx))
1677 return;
1678
1679 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1680 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1681 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001682 return;
1683 }
1684
Yun Parkb187d542016-11-14 18:10:04 -08001685 hdd_debug("STAT REQ Reason %d", reason);
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 */
1707void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1708{
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 */
1722void hdd_ipa_uc_sharing_stats_request(hdd_adapter_t *adapter,
1723 uint8_t reset_stats)
1724{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001725 struct hdd_context *pHddCtx;
Yun Park637d6482016-10-05 10:51:33 -07001726 struct hdd_ipa_priv *hdd_ipa;
1727
1728 if (!adapter)
1729 return;
1730
1731 pHddCtx = adapter->pHddCtx;
1732 hdd_ipa = pHddCtx->hdd_ipa;
1733 if (!hdd_ipa_is_enabled(pHddCtx) ||
1734 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1735 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 */
1759void hdd_ipa_uc_set_quota(hdd_adapter_t *adapter, uint8_t set_quota,
1760 uint64_t quota_bytes)
1761{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001762 struct hdd_context *pHddCtx;
Yun Park637d6482016-10-05 10:51:33 -07001763 struct hdd_ipa_priv *hdd_ipa;
1764
1765 if (!adapter)
1766 return;
1767
1768 pHddCtx = adapter->pHddCtx;
1769 hdd_ipa = pHddCtx->hdd_ipa;
1770 if (!hdd_ipa_is_enabled(pHddCtx) ||
1771 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1772 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{
1855 int result;
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 Parkb4f591d2017-03-29 15:51:01 -07001859 result = cdp_ipa_enable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301861 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001862 "Enable PIPE fail, code %d", result);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001863 return result;
1864 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001865
Leo Change3e49442015-10-26 20:07:13 -07001866 hdd_ipa->ipa_pipes_down = false;
Yun Parkb4f591d2017-03-29 15:51:01 -07001867
1868 cdp_ipa_enable_autonomy(soc, (struct cdp_pdev *)pdev);
1869
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870 return 0;
1871}
1872
1873/**
1874 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1875 * @hdd_ipa: Global HDD IPA context
1876 *
1877 * Return: 0 on success, negative errno if error
1878 */
1879static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1880{
Yun Parkb4f591d2017-03-29 15:51:01 -07001881 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1882 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001883 int result;
1884
Leo Change3e49442015-10-26 20:07:13 -07001885 hdd_ipa->ipa_pipes_down = true;
1886
Yun Parkb4f591d2017-03-29 15:51:01 -07001887 cdp_ipa_disable_autonomy(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001888
Yun Parkb4f591d2017-03-29 15:51:01 -07001889 result = cdp_ipa_disable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001890 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301891 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001892 "Disable WDI PIPE fail, code %d", result);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001893 return result;
1894 }
1895
1896 return 0;
1897}
1898
1899/**
1900 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1901 * @hdd_ipa: Global HDD IPA context
1902 *
1903 * Return: 0 on success, negative errno if error
1904 */
1905static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1906{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001907 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07001908
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001909 hdd_ipa->activated_fw_pipe = 0;
1910 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001911
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001912 /* If RM feature enabled
1913 * Request PROD Resource first
Yun Parkb4f591d2017-03-29 15:51:01 -07001914 * PROD resource may return sync or async manners */
1915 if (hdd_ipa_is_rm_enabled(hdd_ctx)) {
Yun Park4cab6ee2015-10-27 11:43:40 -07001916 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1917 /* RM PROD request sync return
1918 * enable pipe immediately
1919 */
1920 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301921 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001922 "IPA WDI Pipe activation failed");
Yun Park4cab6ee2015-10-27 11:43:40 -07001923 hdd_ipa->resource_loading = false;
1924 return -EBUSY;
1925 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001926 }
1927 } else {
1928 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001929 * Just enabled all the PIPEs
1930 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001931 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301932 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001933 "IPA WDI Pipe activation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001934 hdd_ipa->resource_loading = false;
1935 return -EBUSY;
1936 }
1937 hdd_ipa->resource_loading = false;
1938 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001939
Srinivas Girigowda97852372017-03-06 16:52:59 -08001940 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb4f591d2017-03-29 15:51:01 -07001941 "IPA WDI Pipes activated successfully");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001942 return 0;
1943}
1944
1945/**
1946 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1947 * @hdd_ipa: Global HDD IPA context
1948 *
1949 * Return: None
1950 */
1951static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1952{
Leo Changfdb45c32016-10-28 11:09:23 -07001953 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07001954 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001955
Yun Parkb4f591d2017-03-29 15:51:01 -07001956 if (!pdev) {
Yun Park7c4f31b2016-11-30 10:09:21 -08001957 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
1958 QDF_ASSERT(0);
1959 return;
1960 }
1961
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962 hdd_ipa->resource_unloading = true;
Yun Parkb4f591d2017-03-29 15:51:01 -07001963 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW RX PIPE");
1964 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, false);
1965 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW TX PIPE");
1966 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967}
1968
1969/**
1970 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
1971 * @context: User context registered with TL (the IPA Global context is
1972 * registered
1973 * @rxpkt: Packet containing the notification
1974 * @staid: ID of the station associated with the packet
1975 *
1976 * Return: None
1977 */
1978static void
1979hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
1980{
1981 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301982 QDF_STATUS status = QDF_STATUS_SUCCESS;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001983 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984
1985 /*
1986 * When SSR is going on or driver is unloading, just return.
1987 */
Yun Parkb4f591d2017-03-29 15:51:01 -07001988 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301989 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001990 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991
Yun Parkb4f591d2017-03-29 15:51:01 -07001992 if (!hdd_ipa_is_rm_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 return;
1994
Srinivas Girigowda97852372017-03-06 16:52:59 -08001995 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001996 __func__, event);
1997
1998 switch (event) {
1999 case IPA_RM_RESOURCE_GRANTED:
2000 /* Differed RM Granted */
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302001 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002002 if ((false == hdd_ipa->resource_unloading) &&
2003 (!hdd_ipa->activated_fw_pipe)) {
2004 hdd_ipa_uc_enable_pipes(hdd_ipa);
2005 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302006 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002007 break;
2008
2009 case IPA_RM_RESOURCE_RELEASED:
2010 /* Differed RM Released */
2011 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012 break;
2013
2014 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302015 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002016 "%s, invalid event code %d", __func__, event);
2017 break;
2018 }
2019}
2020
2021/**
2022 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2023 * @hdd_ipa: Global HDD IPA context
2024 * @event: IPA resource manager event to be deferred
2025 *
2026 * This function is called when a resource manager event is received
2027 * from firmware in interrupt context. This function will defer the
2028 * handling to the OL RX thread
2029 *
2030 * Return: None
2031 */
2032static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2033{
2034 enum ipa_rm_event event;
2035 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2036 struct uc_rm_work_struct, work);
2037 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2038 struct hdd_ipa_priv, uc_rm_work);
2039
2040 cds_ssr_protect(__func__);
2041 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002042 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043 "%s, posted event %d", __func__, event);
2044
2045 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2046 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002047}
2048
2049/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002050 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
Yun Parkb4f591d2017-03-29 15:51:01 -07002051 * @hdd_ipa: hdd ipa local context
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002052 *
2053 * Will handle IPA UC image loaded indication comes from IPA kernel
2054 *
2055 * Return: None
2056 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002057static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *hdd_ipa)
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002058{
Yun Parkb4f591d2017-03-29 15:51:01 -07002059 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2060 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002061 struct hdd_context *hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07002062 QDF_STATUS status;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002063
2064 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
Yun Parkb4f591d2017-03-29 15:51:01 -07002065 if (true == hdd_ipa->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002066 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002067 __func__);
2068 return;
2069 }
2070
Yun Parkb4f591d2017-03-29 15:51:01 -07002071 hdd_ctx = hdd_ipa->hdd_ctx;
2072 hdd_ipa->uc_loaded = true;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002073
Yun Parkb4f591d2017-03-29 15:51:01 -07002074 /* Connect pipe */
2075 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
2076 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
2077 hdd_ipa_wdi_meter_notifier_cb,
2078 hdd_ctx->config->IpaDescSize,
2079 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
2080 &hdd_ipa->tx_pipe_handle,
2081 &hdd_ipa->rx_pipe_handle);
2082 if (status) {
2083 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2084 "Failure to setup IPA pipes (status=%d)",
2085 status);
2086 return;
2087 }
2088
2089 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002090
2091 /* If already any STA connected, enable IPA/FW PIPEs */
Yun Parkb4f591d2017-03-29 15:51:01 -07002092 if (hdd_ipa->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002093 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002094 "Client already connected, enable IPA/FW PIPEs");
Yun Parkb4f591d2017-03-29 15:51:01 -07002095 hdd_ipa_uc_handle_first_con(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002096 }
2097}
2098
2099/**
Yun Park637d6482016-10-05 10:51:33 -07002100 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2101 * @hdd_ctx: Global HDD context
2102 * @op_msg: operation message received from firmware
2103 *
2104 * Return: QDF_STATUS enumeration
2105 */
2106#ifdef FEATURE_METERING
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002107static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002108 struct op_msg_type *op_msg)
2109{
2110 struct op_msg_type *msg = op_msg;
2111 struct ipa_uc_sharing_stats *uc_sharing_stats;
2112 struct ipa_uc_quota_rsp *uc_quota_rsp;
2113 struct ipa_uc_quota_ind *uc_quota_ind;
2114 struct hdd_ipa_priv *hdd_ipa;
2115 hdd_adapter_t *adapter;
2116
2117 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2118
2119 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2120 /* fill-up ipa_uc_sharing_stats structure from FW */
2121 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2122 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2123
2124 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2125 sizeof(struct ipa_uc_sharing_stats));
2126
2127 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2128
2129 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2130 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2131 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2132 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2133 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2134 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2135 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2136 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2137 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2138 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2139 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2140 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2141 /* received set quota response */
2142 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2143 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2144
2145 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2146 sizeof(struct ipa_uc_quota_rsp));
2147
2148 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2149 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2150 "%s: success=%d, quota_bytes=%llu",
2151 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2152 hdd_ipa->ipa_quota_rsp.success,
2153 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2154 hdd_ipa->ipa_quota_rsp.quota_lo);
2155 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2156 /* hit quota limit */
2157 uc_quota_ind = (struct ipa_uc_quota_ind *)
2158 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2159
2160 hdd_ipa->ipa_quota_ind.quota_bytes =
2161 uc_quota_ind->quota_bytes;
2162
2163 /* send quota exceeded indication to IPA */
2164 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2165 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2166 hdd_ipa->ipa_quota_ind.quota_bytes);
2167
2168 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2169 if (adapter)
2170 ipa_broadcast_wdi_quota_reach_ind(
2171 adapter->dev->ifindex,
2172 uc_quota_ind->quota_bytes);
2173 else
2174 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2175 "Failed quota_reach_ind: NULL adapter");
2176 } else {
2177 return QDF_STATUS_E_INVAL;
2178 }
2179
2180 return QDF_STATUS_SUCCESS;
2181}
2182#else
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002183static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002184 struct op_msg_type *op_msg)
2185{
2186 return QDF_STATUS_E_INVAL;
2187}
2188#endif
2189
2190/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002191 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2192 * @op_msg: operation message received from firmware
2193 * @usr_ctxt: user context registered with TL (we register the HDD Global
2194 * context)
2195 *
2196 * Return: None
2197 */
2198static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2199{
2200 struct op_msg_type *msg = op_msg;
2201 struct ipa_uc_fw_stats *uc_fw_stat;
2202 struct IpaHwStatsWDIInfoData_t ipa_stat;
2203 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002204 struct hdd_context *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302205 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002206
2207 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302208 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002209 return;
2210 }
2211
2212 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302213 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002214 "%s, INVALID OPCODE %d", __func__, msg->op_code);
jiadd91a6842017-08-01 14:46:02 +08002215 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002216 return;
2217 }
2218
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002219 hdd_ctx = (struct hdd_context *) usr_ctxt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002220
2221 /*
2222 * When SSR is going on or driver is unloading, just return.
2223 */
2224 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302225 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302226 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002227 return;
2228 }
2229
2230 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2231
Govind Singhb6a89772016-08-12 11:23:35 +05302232 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002233 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002234
2235 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2236 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302237 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002238 hdd_ipa->activated_fw_pipe++;
2239 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2240 hdd_ipa->resource_loading = false;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002241 if (hdd_ipa->wdi_enabled == false) {
2242 hdd_ipa->wdi_enabled = true;
2243 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2244 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2245 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002246 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002247 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002248 if (hdd_ipa->pending_cons_req)
2249 ipa_rm_notify_completion(
2250 IPA_RM_RESOURCE_GRANTED,
2251 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002252 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002253 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302254 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002255 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002256 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302257 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002258 hdd_ipa->activated_fw_pipe--;
2259 if (!hdd_ipa->activated_fw_pipe) {
2260 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002261 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2262 ipa_rm_release_resource(
2263 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002264 /*
2265 * Sync return success from IPA
2266 * Enable/resume all the PIPEs
2267 */
Yun Park5b635012015-12-02 15:05:01 -08002268 hdd_ipa->resource_unloading = false;
2269 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2270 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002271 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302272 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002273 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002274 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002275 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302276 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002277 "==== IPA_UC WLAN_HOST RX ====\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002278 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08002279 "NUM TX FWD OK : %llu\n"
2280 "NUM TX FWD ERR : %llu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002281 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08002282 hdd_ipa->stats.num_tx_fwd_ok,
2283 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302284 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002285 "==== IPA_UC WLAN_HOST CONTROL ====\n"
2286 "SAP NUM STAs: %d\n"
2287 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08002288 "CONCURRENT MODE: %s\n"
2289 "TX PIPE HDL: 0x%x\n"
2290 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002291 "RSC LOADING : %d\n"
2292 "RSC UNLOADING : %d\n"
2293 "PNDNG CNS RQT : %d",
2294 hdd_ipa->sap_num_connected_sta,
2295 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08002296 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002297 hdd_ipa->tx_pipe_handle,
2298 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08002299 hdd_ipa->resource_loading,
2300 hdd_ipa->resource_unloading,
2301 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002302
2303 /* STATs from FW */
2304 uc_fw_stat = (struct ipa_uc_fw_stats *)
2305 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302306 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002307 "==== IPA_UC WLAN_FW TX ====\n"
2308 "COMP RING BASE: 0x%x\n"
2309 "COMP RING SIZE: %d\n"
2310 "COMP RING DBELL : 0x%x\n"
2311 "COMP RING DBELL IND VAL : %d\n"
2312 "COMP RING DBELL CACHED VAL : %d\n"
2313 "COMP RING DBELL CACHED VAL : %d\n"
2314 "PKTS ENQ : %d\n"
2315 "PKTS COMP : %d\n"
2316 "IS SUSPEND : %d\n"
2317 "RSVD : 0x%x",
2318 uc_fw_stat->tx_comp_ring_base,
2319 uc_fw_stat->tx_comp_ring_size,
2320 uc_fw_stat->tx_comp_ring_dbell_addr,
2321 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2322 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2323 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2324 uc_fw_stat->tx_pkts_enqueued,
2325 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002326 uc_fw_stat->tx_is_suspend,
2327 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302328 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329 "==== IPA_UC WLAN_FW RX ====\n"
2330 "IND RING BASE: 0x%x\n"
2331 "IND RING SIZE: %d\n"
2332 "IND RING DBELL : 0x%x\n"
2333 "IND RING DBELL IND VAL : %d\n"
2334 "IND RING DBELL CACHED VAL : %d\n"
2335 "RDY IND ADDR : 0x%x\n"
2336 "RDY IND CACHE VAL : %d\n"
2337 "RFIL IND : %d\n"
2338 "NUM PKT INDICAT : %d\n"
2339 "BUF REFIL : %d\n"
2340 "NUM DROP NO SPC : %d\n"
2341 "NUM DROP NO BUF : %d\n"
2342 "IS SUSPND : %d\n"
2343 "RSVD : 0x%x\n",
2344 uc_fw_stat->rx_ind_ring_base,
2345 uc_fw_stat->rx_ind_ring_size,
2346 uc_fw_stat->rx_ind_ring_dbell_addr,
2347 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2348 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2349 uc_fw_stat->rx_ind_ring_rdidx_addr,
2350 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2351 uc_fw_stat->rx_refill_idx,
2352 uc_fw_stat->rx_num_pkts_indicated,
2353 uc_fw_stat->rx_buf_refilled,
2354 uc_fw_stat->rx_num_ind_drop_no_space,
2355 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002356 uc_fw_stat->rx_is_suspend,
2357 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002358 /* STATs from IPA */
2359 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302360 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002361 "==== IPA_UC IPA TX ====\n"
2362 "NUM PROCD : %d\n"
2363 "CE DBELL : 0x%x\n"
2364 "NUM DBELL FIRED : %d\n"
2365 "COMP RNG FULL : %d\n"
2366 "COMP RNG EMPT : %d\n"
2367 "COMP RNG USE HGH : %d\n"
2368 "COMP RNG USE LOW : %d\n"
2369 "BAM FIFO FULL : %d\n"
2370 "BAM FIFO EMPT : %d\n"
2371 "BAM FIFO USE HGH : %d\n"
2372 "BAM FIFO USE LOW : %d\n"
2373 "NUM DBELL : %d\n"
2374 "NUM UNEXP DBELL : %d\n"
2375 "NUM BAM INT HDL : 0x%x\n"
2376 "NUM BAM INT NON-RUN : 0x%x\n"
2377 "NUM QMB INT HDL : 0x%x",
2378 ipa_stat.tx_ch_stats.num_pkts_processed,
2379 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2380 ipa_stat.tx_ch_stats.num_db_fired,
2381 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2382 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2383 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2384 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2385 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2386 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2387 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2388 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2389 ipa_stat.tx_ch_stats.num_db,
2390 ipa_stat.tx_ch_stats.num_unexpected_db,
2391 ipa_stat.tx_ch_stats.num_bam_int_handled,
2392 ipa_stat.tx_ch_stats.
2393 num_bam_int_in_non_runnning_state,
2394 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2395
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302396 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002397 "==== IPA_UC IPA RX ====\n"
2398 "MAX OST PKT : %d\n"
2399 "NUM PKT PRCSD : %d\n"
2400 "RNG RP : 0x%x\n"
2401 "COMP RNG FULL : %d\n"
2402 "COMP RNG EMPT : %d\n"
2403 "COMP RNG USE HGH : %d\n"
2404 "COMP RNG USE LOW : %d\n"
2405 "BAM FIFO FULL : %d\n"
2406 "BAM FIFO EMPT : %d\n"
2407 "BAM FIFO USE HGH : %d\n"
2408 "BAM FIFO USE LOW : %d\n"
2409 "NUM DB : %d\n"
2410 "NUM UNEXP DB : %d\n"
2411 "NUM BAM INT HNDL : 0x%x\n",
2412 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2413 ipa_stat.rx_ch_stats.num_pkts_processed,
2414 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2415 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2416 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2417 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2418 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2419 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2420 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2421 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2422 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2423 ipa_stat.rx_ch_stats.num_db,
2424 ipa_stat.rx_ch_stats.num_unexpected_db,
2425 ipa_stat.rx_ch_stats.num_bam_int_handled);
2426 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2427 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2428 /* STATs from FW */
2429 uc_fw_stat = (struct ipa_uc_fw_stats *)
2430 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302431 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2433 uc_fw_stat->tx_pkts_completed,
2434 hdd_ipa->ipa_p_tx_packets);
2435 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2436 (uc_fw_stat->rx_num_ind_drop_no_space +
2437 uc_fw_stat->rx_num_ind_drop_no_buf +
2438 uc_fw_stat->rx_num_pkts_indicated),
2439 hdd_ipa->ipa_p_rx_packets);
2440
2441 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2442 hdd_ipa->ipa_p_rx_packets =
2443 (uc_fw_stat->rx_num_ind_drop_no_space +
2444 uc_fw_stat->rx_num_ind_drop_no_buf +
2445 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302446 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002447 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2448 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2449 hdd_ipa_uc_loaded_handler(hdd_ipa);
2450 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002451 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2452 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2453 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002454 }
Yun Park8957d802017-01-25 12:27:29 -08002455
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302456 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002457}
2458
2459
2460/**
2461 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2462 * @adapter: device adapter instance
2463 * @offload_type: MCC or SCC
2464 * @enable: TX offload enable or disable
2465 *
2466 * Return: none
2467 */
2468static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002469 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002470{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002471 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002472 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002473 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002474 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002475
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002476 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002477 return;
2478
Yun Park8292dcb2016-10-07 16:46:06 -07002479 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002480 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002481
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002482 if (!iface_context) {
2483 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2484 "Interface context is NULL");
2485 return;
2486 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08002487 if (session_id >= CSR_ROAM_SESSION_MAX) {
2488 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2489 "invalid session id: %d", session_id);
2490 return;
2491 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002492 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002493 /* IPA offload status is already set as desired */
2494 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002495 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002496 "IPA offload status is already set",
2497 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002498 return;
2499 }
2500
Yun Park4540e862016-11-10 16:30:06 -08002501 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2502 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2503 "invalid session id: %d, offload_type=%d, enable=%d",
2504 adapter->sessionId, offload_type, enable);
2505 return;
2506 }
2507
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302508 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002509 sizeof(ipa_offload_enable_disable));
2510 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002511 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002512 ipa_offload_enable_disable.enable = enable;
2513
Srinivas Girigowda97852372017-03-06 16:52:59 -08002514 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park8292dcb2016-10-07 16:46:06 -07002515 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002516 ipa_offload_enable_disable.offload_type,
2517 ipa_offload_enable_disable.vdev_id,
2518 ipa_offload_enable_disable.enable);
2519
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302520 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002521 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2522 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302523 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002524 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
2525 "Failure to enable IPA offload",
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002526 ipa_offload_enable_disable.offload_type,
2527 ipa_offload_enable_disable.vdev_id,
2528 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002529 } else {
2530 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002531 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002532 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002533 }
2534}
2535
2536/**
2537 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2538 * @work: uC OP work
2539 *
2540 * Return: None
2541 */
2542static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2543{
2544 struct op_msg_type *msg;
2545 struct uc_op_work_struct *uc_op_work = container_of(work,
2546 struct uc_op_work_struct, work);
2547 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2548
2549 cds_ssr_protect(__func__);
2550
2551 msg = uc_op_work->msg;
2552 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002553 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002554 "%s, posted msg %d", __func__, msg->op_code);
2555
2556 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2557
2558 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002559}
2560
2561/**
2562 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2563 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2564 * @op_msg: operation message received from firmware
2565 * @hdd_ctx: Global HDD context
2566 *
2567 * Return: None
2568 */
2569static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2570{
2571 struct hdd_ipa_priv *hdd_ipa;
2572 struct op_msg_type *msg;
2573 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302574 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002575
2576 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302577 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002578 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002579
2580 msg = (struct op_msg_type *)op_msg;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002581 hdd_ipa = ((struct hdd_context *)hdd_ctx)->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002582
2583 if (unlikely(!hdd_ipa))
2584 goto end;
2585
2586 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Yun Parkb4f591d2017-03-29 15:51:01 -07002587 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid OP Code (%d)",
2588 msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002589 goto end;
2590 }
2591
2592 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2593 if (uc_op_work->msg)
2594 /* When the same uC OPCODE is already pended, just return */
2595 goto end;
2596
2597 uc_op_work->msg = msg;
2598 schedule_work(&uc_op_work->work);
2599 return;
2600
2601end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302602 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002603}
2604
2605/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002606 * hdd_ipa_init_uc_op_work - init ipa uc op work
2607 * @work: struct work_struct
2608 * @work_handler: work_handler
2609 *
2610 * Return: none
2611 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002612static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002613 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002614{
2615 INIT_WORK(work, work_handler);
2616}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002617
Yun Park637d6482016-10-05 10:51:33 -07002618#ifdef FEATURE_METERING
2619/**
2620 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2621 * IPA calls to get WLAN stats or set quota limit.
2622 * @priv: pointer to private data registered with IPA (we register a
2623 *» pointer to the global IPA context)
2624 * @evt: the IPA event which triggered the callback
2625 * @data: data associated with the event
2626 *
2627 * Return: None
2628 */
2629static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2630 void *data)
2631{
2632 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2633 hdd_adapter_t *adapter = NULL;
2634 struct ipa_get_wdi_sap_stats *wdi_sap_stats;
2635 struct ipa_set_wifi_quota *ipa_set_quota;
2636 int ret = 0;
2637
2638 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2639 return;
2640
2641 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2642
2643 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2644
2645 switch (evt) {
2646 case IPA_GET_WDI_SAP_STATS:
2647 /* fill-up ipa_get_wdi_sap_stats structure after getting
2648 ipa_uc_fw_stats from FW */
2649 wdi_sap_stats = data;
2650
2651 if (!adapter) {
2652 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2653 "IPA uC share stats failed - no adapter");
2654 wdi_sap_stats->stats_valid = 0;
2655 return;
2656 }
2657
2658 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
2659 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
2660 hdd_ipa_uc_sharing_stats_request(adapter,
2661 wdi_sap_stats->reset_stats);
2662 ret = wait_for_completion_timeout(
2663 &hdd_ipa->ipa_uc_sharing_stats_comp,
2664 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2665 if (!ret) {
2666 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2667 "IPA uC share stats request timed out");
2668 wdi_sap_stats->stats_valid = 0;
2669 } else {
2670 wdi_sap_stats->stats_valid = 1;
2671
2672 wdi_sap_stats->ipv4_rx_packets =
2673 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2674 wdi_sap_stats->ipv4_rx_bytes =
2675 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2676 wdi_sap_stats->ipv6_rx_packets =
2677 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2678 wdi_sap_stats->ipv6_rx_bytes =
2679 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
2680 wdi_sap_stats->ipv4_tx_packets =
2681 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
2682 wdi_sap_stats->ipv4_tx_bytes =
2683 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
2684 wdi_sap_stats->ipv6_tx_packets =
2685 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
2686 wdi_sap_stats->ipv6_tx_bytes =
2687 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
2688 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2689 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2690 "IPA_GET_WDI_SAP_STATS",
2691 wdi_sap_stats->stats_valid,
2692 wdi_sap_stats->ipv4_rx_packets,
2693 wdi_sap_stats->ipv4_rx_bytes,
2694 wdi_sap_stats->ipv6_rx_packets,
2695 wdi_sap_stats->ipv6_rx_bytes,
2696 wdi_sap_stats->ipv4_tx_packets,
2697 wdi_sap_stats->ipv4_tx_bytes,
2698 wdi_sap_stats->ipv6_tx_packets,
2699 wdi_sap_stats->ipv6_tx_bytes);
2700 }
2701 break;
2702 case IPA_SET_WIFI_QUOTA:
2703 /* get ipa_set_wifi_quota structure from IPA and pass to FW
2704 through quota_exceeded field in ipa_uc_fw_stats */
2705 ipa_set_quota = data;
2706
2707 if (!adapter) {
2708 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2709 "IPA uC set quota failed - no adapter");
2710 ipa_set_quota->set_valid = 0;
2711 return;
2712 }
2713
2714 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
2715 ipa_set_quota->quota_bytes);
2716
2717 ret = wait_for_completion_timeout(
2718 &hdd_ipa->ipa_uc_set_quota_comp,
2719 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
2720 if (!ret) {
2721 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2722 "IPA uC set quota request timed out");
2723 ipa_set_quota->set_valid = 0;
2724 } else {
2725 ipa_set_quota->quota_bytes =
2726 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
2727 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
2728 ipa_set_quota->set_valid =
2729 hdd_ipa->ipa_quota_rsp.success;
2730 }
2731
2732 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
2733 ipa_set_quota->quota_bytes,
2734 ipa_set_quota->set_valid);
2735 break;
2736 }
2737}
2738
2739/**
2740 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2741 * IPA calls to get WLAN stats or set quota limit.
2742 * @priv: pointer to private data registered with IPA (we register a
Yun Parkb4f591d2017-03-29 15:51:01 -07002743 * pointer to the global IPA context)
Yun Park637d6482016-10-05 10:51:33 -07002744 * @evt: the IPA event which triggered the callback
2745 * @data: data associated with the event
2746 *
2747 * Return: None
2748 */
2749static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2750 void *data)
2751{
2752 cds_ssr_protect(__func__);
2753 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
2754 cds_ssr_unprotect(__func__);
2755}
2756
Yun Parkb4f591d2017-03-29 15:51:01 -07002757static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07002758{
Yun Park637d6482016-10-05 10:51:33 -07002759 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
2760 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
2761}
2762#else
Yun Parkb4f591d2017-03-29 15:51:01 -07002763static void hdd_ipa_wdi_meter_notifier_cb(void)
2764{
2765}
2766
2767static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07002768{
2769}
2770#endif
2771
Rajeev Kumar217f2172016-01-06 18:11:55 -08002772/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002773 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2774 * @hdd_ctx: Global HDD context
2775 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002776 * This function is called to update IPA pipe configuration with resources
2777 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
2778 * (cds_enable)
2779 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302780 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002781 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002782QDF_STATUS hdd_ipa_uc_ol_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002783{
Yun Parkb4f591d2017-03-29 15:51:01 -07002784 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07002785 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002786 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkb4f591d2017-03-29 15:51:01 -07002787 uint8_t i;
2788 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002789
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002790 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2791 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002792
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002793 ENTER();
2794 /* Do only IPA Pipe specific configuration here. All one time
2795 * initialization wrt IPA UC shall in hdd_ipa_init and those need
2796 * to be reinit at SSR shall in be SSR deinit / reinit functions.
2797 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002798 if (!pdev || !soc) {
2799 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkb4f591d2017-03-29 15:51:01 -07002800 status = QDF_STATUS_E_FAILURE;
Yun Parkbaa62862017-01-18 13:43:34 -08002801 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002802 }
Yun Parkb4f591d2017-03-29 15:51:01 -07002803 if (cdp_ipa_get_resource(soc, (struct cdp_pdev *)pdev)) {
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002804 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2805 "IPA UC resource alloc fail");
2806 return QDF_STATUS_E_FAILURE;
2807 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002808
Yun Parkb4f591d2017-03-29 15:51:01 -07002809 if (true == hdd_ipa->uc_loaded) {
2810 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
2811 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
2812 hdd_ipa_wdi_meter_notifier_cb,
2813 hdd_ctx->config->IpaDescSize,
2814 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
2815 &hdd_ipa->tx_pipe_handle,
2816 &hdd_ipa->rx_pipe_handle);
2817 if (status) {
Yun Parkbaa62862017-01-18 13:43:34 -08002818 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002819 "Failure to setup IPA pipes (status=%d)",
2820 status);
2821 return QDF_STATUS_E_FAILURE;
Yun Parkbaa62862017-01-18 13:43:34 -08002822 }
Yun Park637d6482016-10-05 10:51:33 -07002823
Yun Parkb4f591d2017-03-29 15:51:01 -07002824 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
2825 hdd_ipa_init_metering(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002826 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002827
Yun Parkb4f591d2017-03-29 15:51:01 -07002828 cdp_ipa_register_op_cb(soc, (struct cdp_pdev *)pdev,
Yun Parkbaa62862017-01-18 13:43:34 -08002829 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
2830
Yun Parkb4f591d2017-03-29 15:51:01 -07002831 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
2832 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
2833 hdd_ipa_uc_fw_op_event_handler);
2834 hdd_ipa->uc_op_work[i].msg = NULL;
2835 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836
Yun Parkbaa62862017-01-18 13:43:34 -08002837fail_return:
2838 EXIT();
Yun Parkb4f591d2017-03-29 15:51:01 -07002839 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002840}
2841
Leo Change3e49442015-10-26 20:07:13 -07002842/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302843 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
2844 * @hdd_ctx: Global HDD context
2845 *
2846 * Return: 0 on success, negativer errno on error
2847 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002848int hdd_ipa_uc_ol_deinit(struct hdd_context *hdd_ctx)
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302849{
2850 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
2851 int ret = 0;
Yun Parkb4f591d2017-03-29 15:51:01 -07002852 QDF_STATUS status;
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302853
2854 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2855 return ret;
2856
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05302857 if (!hdd_ipa->ipa_pipes_down)
2858 hdd_ipa_uc_disable_pipes(hdd_ipa);
2859
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302860 if (true == hdd_ipa->uc_loaded) {
Yun Parkb4f591d2017-03-29 15:51:01 -07002861 status = cdp_ipa_cleanup(cds_get_context(QDF_MODULE_ID_SOC),
2862 hdd_ipa->tx_pipe_handle,
2863 hdd_ipa->rx_pipe_handle);
2864 if (status) {
2865 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2866 "Failure to cleanup IPA pipes (status=%d)",
2867 status);
2868 return -EFAULT;
2869 }
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302870 }
2871
2872 return ret;
2873}
2874
2875/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002876 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002877 * @hdd_ctx: hdd main context
2878 *
2879 * Force shutdown IPA pipe
2880 * Independent of FW pipe status, IPA pipe shutdonw progress
2881 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2882 * independent from FW pipe status
2883 *
2884 * Return: NONE
2885 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002886static void __hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002887{
2888 struct hdd_ipa_priv *hdd_ipa;
2889
2890 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2891 return;
2892
2893 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2894 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302895 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002896 "IPA pipes are not down yet, force shutdown");
Leo Change3e49442015-10-26 20:07:13 -07002897 hdd_ipa_uc_disable_pipes(hdd_ipa);
2898 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002899 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb4f591d2017-03-29 15:51:01 -07002900 "IPA pipes are down, do nothing");
Leo Change3e49442015-10-26 20:07:13 -07002901 }
Leo Change3e49442015-10-26 20:07:13 -07002902}
2903
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002904/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002905 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2906 * __hdd_ipa_uc_force_pipe_shutdown
2907 * @hdd_ctx: hdd main context
2908 *
2909 * Force shutdown IPA pipe
2910 * Independent of FW pipe status, IPA pipe shutdonw progress
2911 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2912 * independent from FW pipe status
2913 *
2914 * Return: NONE
2915 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002916void hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002917{
2918 cds_ssr_protect(__func__);
2919 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2920 cds_ssr_unprotect(__func__);
2921}
2922
2923/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302924 * hdd_ipa_msg_free_fn() - Free an IPA message
2925 * @buff: pointer to the IPA message
2926 * @len: length of the IPA message
2927 * @type: type of IPA message
2928 *
2929 * Return: None
2930 */
2931static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2932{
Srinivas Girigowda97852372017-03-06 16:52:59 -08002933 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05302934 ghdd_ipa->stats.num_free_msg++;
2935 qdf_mem_free(buff);
2936}
2937
Govind Singh9c58eba2016-09-02 16:23:06 +05302938/**
jge62037862016-12-09 10:44:33 +08002939 * hdd_ipa_uc_send_evt() - send event to ipa
2940 * @hdd_ctx: pointer to hdd context
2941 * @type: event type
2942 * @mac_addr: pointer to mac address
2943 *
2944 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05302945 *
2946 * Return: 0 - Success
2947 */
jge62037862016-12-09 10:44:33 +08002948static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
2949 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05302950{
jge62037862016-12-09 10:44:33 +08002951 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05302952 struct ipa_msg_meta meta;
2953 struct ipa_wlan_msg *msg;
2954 int ret = 0;
jge62037862016-12-09 10:44:33 +08002955
2956 meta.msg_len = sizeof(struct ipa_wlan_msg);
2957 msg = qdf_mem_malloc(meta.msg_len);
2958 if (msg == NULL) {
2959 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2960 "msg allocation failed");
2961 return -ENOMEM;
2962 }
2963
2964 meta.msg_type = type;
2965 strlcpy(msg->name, adapter->dev->name,
2966 IPA_RESOURCE_NAME_MAX);
2967 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002968 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
jge62037862016-12-09 10:44:33 +08002969 msg->name, meta.msg_type);
2970 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2971 if (ret) {
2972 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2973 "%s: Evt: %d fail:%d",
2974 msg->name, meta.msg_type, ret);
2975 qdf_mem_free(msg);
2976 return ret;
2977 }
2978
2979 hdd_ipa->stats.num_send_msg++;
2980
2981 return ret;
2982}
2983
2984/**
2985 * hdd_ipa_uc_disconnect_client() - send client disconnect event
2986 * @hdd_ctx: pointer to hdd adapter
2987 *
2988 * Send disconnect client event to IPA driver during SSR
2989 *
2990 * Return: 0 - Success
2991 */
2992static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
2993{
2994 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2995 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05302996 int i;
2997
2998 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2999 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
3000 continue;
3001 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08003002 (!adapter->aStaInfo[i].isDeauthInProgress) &&
3003 hdd_ipa->sap_num_connected_sta) {
3004 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
3005 adapter->aStaInfo[i].macAddrSTA.bytes);
3006 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303007 }
3008 }
3009
3010 return ret;
3011}
3012
3013/**
jge62037862016-12-09 10:44:33 +08003014 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3015 * @hdd_ctx: pointer to hdd adapter
3016 *
3017 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303018 *
3019 * Return: 0 - Success
3020 */
jge62037862016-12-09 10:44:33 +08003021
3022static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
3023{
3024 int ret = 0;
3025
3026 if (adapter->ipa_context)
3027 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3028 adapter->dev->dev_addr);
3029
3030 return ret;
3031}
3032
jge62037862016-12-09 10:44:33 +08003033/**
3034 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3035 * @hdd_ctx: pointer to hdd adapter
3036 *
3037 * Send disconnect sta event to IPA driver during SSR
3038 *
3039 * Return: 0 - Success
3040 */
3041static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
3042{
3043 hdd_station_ctx_t *pHddStaCtx;
3044 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3045 int ret = 0;
3046
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003047 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003048 hdd_ipa->sta_connected) {
3049 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
3050 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003051 pHddStaCtx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003052 }
3053
3054 return ret;
3055}
jge62037862016-12-09 10:44:33 +08003056
3057/**
3058 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3059 * @hdd_ctx: pointer to hdd context
3060 *
3061 * Send disconnect event to IPA driver during SSR
3062 *
3063 * Return: 0 - Success
3064 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003065static int hdd_ipa_uc_disconnect(struct hdd_context *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303066{
3067 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
3068 QDF_STATUS status;
3069 hdd_adapter_t *adapter;
3070 int ret = 0;
3071
Govind Singh9c58eba2016-09-02 16:23:06 +05303072 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
3073 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
3074 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08003075 if (adapter->device_mode == QDF_SAP_MODE) {
3076 hdd_ipa_uc_disconnect_client(adapter);
3077 hdd_ipa_uc_disconnect_ap(adapter);
3078 } else if (adapter->device_mode == QDF_STA_MODE) {
3079 hdd_ipa_uc_disconnect_sta(adapter);
3080 }
3081
Govind Singh9c58eba2016-09-02 16:23:06 +05303082 status = hdd_get_next_adapter(
3083 hdd_ctx, adapter_node, &next);
3084 adapter_node = next;
3085 }
3086
3087 return ret;
3088}
3089
3090/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003091 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003092 *
3093 * Deinit basic IPA UC host side to be in sync reloaded FW during
3094 * SSR
3095 *
3096 * Return: 0 - Success
3097 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003098static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003099{
3100 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3101 int idx;
3102 struct hdd_ipa_iface_context *iface_context;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003103 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003104
Arun Khandavallicc544b32017-01-30 19:52:16 +05303105 if (!hdd_ipa)
3106 return 0;
3107
3108 hdd_ctx = hdd_ipa->hdd_ctx;
3109 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003110 return 0;
3111
jge62037862016-12-09 10:44:33 +08003112 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303113 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003114
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003115 /* Clean up HDD IPA interfaces */
3116 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3117 (idx < HDD_IPA_MAX_IFACE); idx++) {
3118 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003119 if (iface_context->adapter && iface_context->adapter->magic ==
3120 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003121 hdd_ipa_cleanup_iface(iface_context);
3122 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003123 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003124 /* After SSR, wlan driver reloads FW again. But we need to protect
3125 * IPA submodule during SSR transient state. So deinit basic IPA
3126 * UC host side to be in sync with reloaded FW during SSR
3127 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003128
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303129 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003130 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3131 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3132 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3133 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303134 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135
Guolei Bianca144d82016-11-10 11:07:42 +08003136 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3137 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3138
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003139 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
3140 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
3141 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
3142 hdd_ipa->uc_op_work[idx].msg = NULL;
3143 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003144 return 0;
3145}
3146
3147/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003148 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3149 *
3150 * Deinit basic IPA UC host side to be in sync reloaded FW during
3151 * SSR
3152 *
3153 * Return: 0 - Success
3154 */
3155int hdd_ipa_uc_ssr_deinit(void)
3156{
3157 int ret;
3158
3159 cds_ssr_protect(__func__);
3160 ret = __hdd_ipa_uc_ssr_deinit();
3161 cds_ssr_unprotect(__func__);
3162
3163 return ret;
3164}
3165
3166/**
3167 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003168 *
3169 * Init basic IPA UC host side to be in sync with reloaded FW after
3170 * SSR to resume IPA UC operations
3171 *
3172 * Return: 0 - Success
3173 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003174static int __hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003175{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003176
Arun Khandavallicc544b32017-01-30 19:52:16 +05303177 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3178 int i;
3179 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303180
3181 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3182 return 0;
3183
Arun Khandavallicc544b32017-01-30 19:52:16 +05303184 /* Create the interface context */
3185 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3186 iface_context = &hdd_ipa->iface_context[i];
3187 iface_context->hdd_ipa = hdd_ipa;
3188 iface_context->cons_client =
3189 hdd_ipa_adapter_2_client[i].cons_client;
3190 iface_context->prod_client =
3191 hdd_ipa_adapter_2_client[i].prod_client;
3192 iface_context->iface_id = i;
3193 iface_context->adapter = NULL;
3194 }
3195 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3196 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3197 hdd_ipa->vdev_offload_enabled[i] = false;
3198 }
3199
3200 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3201 hdd_ipa->resource_loading = false;
3202 hdd_ipa->resource_unloading = false;
3203 hdd_ipa->sta_connected = 0;
3204 hdd_ipa->ipa_pipes_down = true;
3205 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303206 }
3207
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003208 return 0;
3209}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003210
3211/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003212 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3213 *
3214 * Init basic IPA UC host side to be in sync with reloaded FW after
3215 * SSR to resume IPA UC operations
3216 *
3217 * Return: 0 - Success
3218 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003219int hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003220{
3221 int ret;
3222
3223 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303224 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003225 cds_ssr_unprotect(__func__);
3226
3227 return ret;
3228}
3229
3230/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003231 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3232 * @work: scheduled work
3233 *
3234 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3235 * not want to immediately release the wake lock since the system
3236 * would then potentially try to suspend when there is a healthy data
3237 * rate. Deferred work is scheduled and this function handles the
3238 * work. When this function is called, if the IPA resource is still
3239 * released then we release the wake lock.
3240 *
3241 * Return: None
3242 */
3243static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3244{
3245 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3246 struct hdd_ipa_priv,
3247 wake_lock_work);
3248
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303249 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003250
3251 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3252 goto end;
3253
3254 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303255 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003256 WIFI_POWER_EVENT_WAKELOCK_IPA);
3257
3258end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303259 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003260}
3261
3262/**
3263 * hdd_ipa_rm_request() - Request resource from IPA
3264 * @hdd_ipa: Global HDD IPA context
3265 *
3266 * Return: 0 on success, negative errno on error
3267 */
3268static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3269{
3270 int ret = 0;
3271
3272 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3273 return 0;
3274
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303275 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003276
3277 switch (hdd_ipa->rm_state) {
3278 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303279 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003280 return 0;
3281 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303282 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003283 return -EINPROGRESS;
3284 case HDD_IPA_RM_RELEASED:
3285 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3286 break;
3287 }
3288
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303289 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003290
3291 ret = ipa_rm_inactivity_timer_request_resource(
3292 IPA_RM_RESOURCE_WLAN_PROD);
3293
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303294 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003295 if (ret == 0) {
3296 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3297 hdd_ipa->stats.num_rm_grant_imm++;
3298 }
3299
3300 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3301 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303302 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003303 WIFI_POWER_EVENT_WAKELOCK_IPA);
3304 hdd_ipa->wake_lock_released = false;
3305 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303306 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003307
3308 return ret;
3309}
3310
3311/**
3312 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3313 * @hdd_ipa: Global HDD IPA context
3314 *
3315 * Return: 0 if resources released, negative errno otherwise
3316 */
3317static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3318{
3319 int ret = 0;
3320
3321 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3322 return 0;
3323
3324 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3325 return -EAGAIN;
3326
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303327 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003328
Nirav Shahcbc6d722016-03-01 16:24:53 +05303329 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303330 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003331 return -EAGAIN;
3332 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303333 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003334
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303335 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003336 switch (hdd_ipa->rm_state) {
3337 case HDD_IPA_RM_GRANTED:
3338 break;
3339 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303340 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003341 return -EINPROGRESS;
3342 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303343 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003344 return 0;
3345 }
3346
3347 /* IPA driver returns immediately so set the state here to avoid any
3348 * race condition.
3349 */
3350 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3351 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303352 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003353
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003354 ret = ipa_rm_inactivity_timer_release_resource(
3355 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003356
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303357 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003358 if (unlikely(ret != 0)) {
3359 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3360 WARN_ON(1);
3361 }
3362
3363 /*
3364 * If wake_lock is released immediately, kernel would try to suspend
3365 * immediately as well, Just avoid ping-pong between suspend-resume
3366 * while there is healthy amount of data transfer going on by
3367 * releasing the wake_lock after some delay.
3368 */
3369 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3370 msecs_to_jiffies
3371 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3372
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303373 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003374
3375 return ret;
3376}
3377
3378/**
3379 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3380 * @user_data: user data registered with IPA
3381 * @event: the IPA resource manager event that occurred
3382 * @data: the data associated with the event
3383 *
3384 * Return: None
3385 */
3386static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3387 unsigned long data)
3388{
3389 struct hdd_ipa_priv *hdd_ipa = user_data;
3390
3391 if (unlikely(!hdd_ipa))
3392 return;
3393
3394 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3395 return;
3396
Srinivas Girigowda97852372017-03-06 16:52:59 -08003397 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003398
3399 switch (event) {
3400 case IPA_RM_RESOURCE_GRANTED:
3401 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3402 /* RM Notification comes with ISR context
3403 * it should be serialized into work queue to avoid
3404 * ISR sleep problem
3405 */
3406 hdd_ipa->uc_rm_work.event = event;
3407 schedule_work(&hdd_ipa->uc_rm_work.work);
3408 break;
3409 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303410 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003411 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303412 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413 hdd_ipa->stats.num_rm_grant++;
3414 break;
3415
3416 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003417 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418 hdd_ipa->resource_unloading = false;
3419 break;
3420
3421 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303422 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423 break;
3424 }
3425}
3426
3427/**
3428 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3429 *
3430 * Callback function registered with IPA that is called when IPA wants
3431 * to release the WLAN consumer resource
3432 *
3433 * Return: 0 if the request is granted, negative errno otherwise
3434 */
3435static int hdd_ipa_rm_cons_release(void)
3436{
3437 return 0;
3438}
3439
3440/**
3441 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3442 *
3443 * Callback function registered with IPA that is called when IPA wants
3444 * to access the WLAN consumer resource
3445 *
3446 * Return: 0 if the request is granted, negative errno otherwise
3447 */
3448static int hdd_ipa_rm_cons_request(void)
3449{
Yun Park4d8b60a2015-10-22 13:59:32 -07003450 int ret = 0;
3451
3452 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303453 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003454 "IPA resource loading in progress");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003455 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003456 ret = -EINPROGRESS;
3457 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303458 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003459 "IPA resource unloading in progress");
Yun Park4d8b60a2015-10-22 13:59:32 -07003460 ghdd_ipa->pending_cons_req = true;
3461 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003462 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003463
3464 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003465}
3466
3467/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003468 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003469 * @hdd_ctx: Global HDD context
3470 * @tx_packets: Number of packets transmitted in the last sample period
3471 * @rx_packets: Number of packets received in the last sample period
3472 *
3473 * Return: 0 on success, negative errno on error
3474 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003475static int __hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003476 uint64_t rx_packets)
3477{
3478 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003479 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003480 struct ipa_rm_perf_profile profile;
Yun Parkb4f591d2017-03-29 15:51:01 -07003481 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003482 int ret;
3483
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003484 if (wlan_hdd_validate_context(hdd_ctx))
3485 return 0;
3486
3487 hdd_ipa = hdd_ctx->hdd_ipa;
3488
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003489 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3490 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3491 return 0;
3492
3493 memset(&profile, 0, sizeof(profile));
3494
3495 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3496 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3497 else if (tx_packets >
3498 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3499 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3500 else
3501 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3502
3503 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3504 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3505 else if (rx_packets >
3506 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3507 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3508 else
3509 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3510
Yun Parkec845302016-12-15 09:22:57 -08003511 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003512 "CONS perf curr: %d, next: %d",
3513 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003514 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003515 "PROD perf curr: %d, next: %d",
3516 hdd_ipa->curr_prod_bw, next_prod_bw);
3517
3518 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003519 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003520 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003521 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS,
3522 next_cons_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003523 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003524 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003525
3526 return ret;
3527 }
3528 hdd_ipa->curr_cons_bw = next_cons_bw;
3529 hdd_ipa->stats.num_cons_perf_req++;
3530 }
3531
3532 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003533 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003534 hdd_ipa->curr_prod_bw, next_prod_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003535 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD,
3536 next_prod_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003537 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003538 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003539 return ret;
3540 }
3541 hdd_ipa->curr_prod_bw = next_prod_bw;
3542 hdd_ipa->stats.num_prod_perf_req++;
3543 }
3544
3545 return 0;
3546}
3547
3548/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003549 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3550 * @hdd_ctx: Global HDD context
3551 * @tx_packets: Number of packets transmitted in the last sample period
3552 * @rx_packets: Number of packets received in the last sample period
3553 *
3554 * Return: 0 on success, negative errno on error
3555 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003556int hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003557 uint64_t rx_packets)
3558{
3559 int ret;
3560
3561 cds_ssr_protect(__func__);
3562 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3563 cds_ssr_unprotect(__func__);
3564
3565 return ret;
3566}
3567
3568/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003569 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3570 * @work: struct work_struct
3571 * @work_handler: work_handler
3572 *
3573 * Return: none
3574 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003575static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3576 work_func_t work_handler)
3577{
3578 INIT_WORK(work, work_handler);
3579}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003580
3581/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003582 * hdd_ipa_setup_rm() - Setup IPA resource management
3583 * @hdd_ipa: Global HDD IPA context
3584 *
3585 * Return: 0 on success, negative errno on error
3586 */
3587static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3588{
3589 struct ipa_rm_create_params create_params = { 0 };
3590 int ret;
3591
3592 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3593 return 0;
3594
Rajeev Kumar217f2172016-01-06 18:11:55 -08003595 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3596 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003597 memset(&create_params, 0, sizeof(create_params));
3598 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3599 create_params.reg_params.user_data = hdd_ipa;
3600 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3601 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3602
3603 ret = ipa_rm_create_resource(&create_params);
3604 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303605 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003606 "Create RM resource failed: %d", ret);
3607 goto setup_rm_fail;
3608 }
3609
3610 memset(&create_params, 0, sizeof(create_params));
3611 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3612 create_params.request_resource = hdd_ipa_rm_cons_request;
3613 create_params.release_resource = hdd_ipa_rm_cons_release;
3614 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3615
3616 ret = ipa_rm_create_resource(&create_params);
3617 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303618 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003619 "Create RM CONS resource failed: %d", ret);
3620 goto delete_prod;
3621 }
3622
3623 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3624 IPA_RM_RESOURCE_APPS_CONS);
3625
3626 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3627 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3628 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303629 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003630 ret);
3631 goto timer_init_failed;
3632 }
3633
3634 /* Set the lowest bandwidth to start with */
3635 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3636
3637 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303638 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003639 "Set perf level failed: %d", ret);
3640 goto set_perf_failed;
3641 }
3642
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303643 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003644 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3645 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303646 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003647 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3648 hdd_ipa->wake_lock_released = true;
3649 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3650
3651 return ret;
3652
3653set_perf_failed:
3654 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3655
3656timer_init_failed:
3657 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3658
3659delete_prod:
3660 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3661
3662setup_rm_fail:
3663 return ret;
3664}
3665
3666/**
3667 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3668 * @hdd_ipa: Global HDD IPA context
3669 *
3670 * Destroys all resources associated with the IPA resource manager
3671 *
3672 * Return: None
3673 */
3674static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3675{
3676 int ret;
3677
3678 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3679 return;
3680
3681 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303682 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003683
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303685 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003686
3687 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3688
3689 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3690 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303691 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003692 "RM PROD resource delete failed %d", ret);
3693
3694 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3695 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303696 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003697 "RM CONS resource delete failed %d", ret);
3698}
3699
tfyu0380a972017-07-13 18:19:37 +08003700#ifdef QCA_CONFIG_SMP
3701static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
3702{
3703 return netif_rx_ni(skb);
3704}
3705#else
3706static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
3707{
3708 struct iphdr *ip_h;
3709 static atomic_t softirq_mitigation_cntr =
3710 ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH);
3711 int result;
3712
3713 ip_h = (struct iphdr *)(skb->data);
3714 if ((skb->protocol == htons(ETH_P_IP)) &&
3715 (ip_h->protocol == IPPROTO_ICMP)) {
3716 result = netif_rx_ni(skb);
3717 } else {
3718 /* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets
3719 * to avoid excessive softirq's.
3720 */
3721 if (atomic_dec_and_test(&softirq_mitigation_cntr)) {
3722 result = netif_rx_ni(skb);
3723 atomic_set(&softirq_mitigation_cntr,
3724 IPA_WLAN_RX_SOFTIRQ_THRESH);
3725 } else {
3726 result = netif_rx(skb);
3727 }
3728 }
3729
3730 return result;
3731}
3732#endif
3733
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003734/**
3735 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3736 * @skb: network buffer
3737 * @adapter: network adapter
3738 *
3739 * Called when a network buffer is received which should not be routed
3740 * to the IPA module.
3741 *
3742 * Return: None
3743 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303744static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745 hdd_adapter_t *adapter)
3746{
tfyu0380a972017-07-13 18:19:37 +08003747 int result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003748 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3749 unsigned int cpu_index;
3750
3751 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003752 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003753 adapter);
3754 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003755 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003756 return;
3757 }
3758
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003759 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003760 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003761 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003762 return;
3763 }
3764
3765 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3766 skb->dev = adapter->dev;
3767 skb->protocol = eth_type_trans(skb, skb->dev);
3768 skb->ip_summed = CHECKSUM_NONE;
3769
3770 cpu_index = wlan_hdd_get_cpu();
3771
3772 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
tfyu0380a972017-07-13 18:19:37 +08003773 result = hdd_ipa_aggregated_rx_ind(skb);
3774 if (result == NET_RX_SUCCESS)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003775 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3776 else
3777 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3778
3779 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003780}
3781
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003782/**
Leo Chang69c39692016-10-12 20:11:12 -07003783 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3784 * @hdd_ipa: pointer to hdd ipa context
3785 * @adapter: network adapter
3786 * @skb: data pointer
3787 *
3788 * if exception packet has set forward bit, copied new packet should be
3789 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3790 * put into pm queue and tx procedure will be differed
3791 *
3792 * Return: None
3793 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003794static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
3795 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003796{
Leo Chang69c39692016-10-12 20:11:12 -07003797 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3798
Leo Chang69c39692016-10-12 20:11:12 -07003799 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
3800 /* WLAN subsystem is in suspend, put int queue */
3801 if (hdd_ipa->suspended) {
3802 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3803 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3804 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003805 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3806 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003807 pm_tx_cb->exception = true;
3808 pm_tx_cb->adapter = adapter;
3809 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003810 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003811 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3812 hdd_ipa->stats.num_tx_queued++;
3813 } else {
3814 /* Resume, put packet into WLAN TX */
3815 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003816 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003817 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3818 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003819 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003820 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003821 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003822 hdd_ipa->ipa_tx_forward++;
3823 }
3824 }
3825}
3826
3827/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003828 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3829 * @hdd_ipa: pointer to HDD IPA struct
3830 * @adapter: hdd adapter pointer
3831 * @desc: Firmware descriptor
3832 * @skb: Data buffer
3833 *
3834 * Return:
3835 * HDD_IPA_FORWARD_PKT_NONE
3836 * HDD_IPA_FORWARD_PKT_DISCARD
3837 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3838 *
3839 */
3840
3841static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3842 struct hdd_ipa_priv *hdd_ipa,
3843 hdd_adapter_t *adapter,
3844 uint8_t desc,
3845 qdf_nbuf_t skb)
3846{
3847 int ret = HDD_IPA_FORWARD_PKT_NONE;
3848
3849 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303850 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003851 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
3852 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303853 /* Drop the packet*/
3854 hdd_ipa->stats.num_tx_fwd_err++;
3855 kfree_skb(skb);
3856 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3857 return ret;
3858 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003859 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3860 "Forward packet to Tx (fw_desc=%d)", desc);
3861 hdd_ipa->ipa_tx_forward++;
3862
3863 if ((desc & FW_RX_DESC_DISCARD_M)) {
3864 hdd_ipa_forward(hdd_ipa, adapter, skb);
3865 hdd_ipa->ipa_rx_internel_drop_count++;
3866 hdd_ipa->ipa_rx_discard++;
3867 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3868 } else {
3869 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003870
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003871 if (cloned_skb)
3872 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3873 else
3874 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3875 "%s: tx skb alloc failed",
3876 __func__);
3877 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3878 }
3879 }
3880
3881 return ret;
3882}
3883
3884/**
Yun Park637d6482016-10-05 10:51:33 -07003885 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003886 * @priv: pointer to private data registered with IPA (we register a
3887 * pointer to the global IPA context)
3888 * @evt: the IPA event which triggered the callback
3889 * @data: data associated with the event
3890 *
3891 * Return: None
3892 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003893static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003894 unsigned long data)
3895{
3896 struct hdd_ipa_priv *hdd_ipa = NULL;
3897 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303898 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003899 uint8_t iface_id;
3900 uint8_t session_id;
3901 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003902 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003903 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003904
3905 hdd_ipa = (struct hdd_ipa_priv *)priv;
3906
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003907 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3908 return;
3909
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003910 switch (evt) {
3911 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303912 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003913
3914 /*
3915 * When SSR is going on or driver is unloading,
3916 * just drop the packets.
3917 */
3918 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
3919 if (0 != status) {
3920 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3921 "Invalid context: drop packet");
3922 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3923 kfree_skb(skb);
3924 return;
3925 }
3926
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3928 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003929 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08003930 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003931 "IPA_RECEIVE: session_id=%u, iface_id=%u",
3932 session_id, iface_id);
3933 } else {
3934 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
3935 }
3936
3937 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303938 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003939 "IPA_RECEIVE: Invalid iface_id: %u",
3940 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003941 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003942 "w2i -- skb",
3943 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003944 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003945 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003946 return;
3947 }
3948
3949 iface_context = &hdd_ipa->iface_context[iface_id];
3950 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08003951 if (!adapter) {
3952 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3953 "IPA_RECEIVE: Adapter is NULL");
3954 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3955 kfree_skb(skb);
3956 return;
3957 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003958
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303959 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003960 "w2i -- skb",
3961 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003962 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3963 hdd_ipa->stats.num_rx_excep++;
3964 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
3965 } else {
3966 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
3967 }
3968
3969 iface_context->stats.num_rx_ipa_excep++;
3970
3971 /* Disable to forward Intra-BSS Rx packets when
3972 * ap_isolate=1 in hostapd.conf
3973 */
Yun Park046101c2016-09-02 15:32:14 -07003974 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003975 /*
3976 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3977 * all Rx packets to IPA uC, which need to be forwarded
3978 * to other interface.
3979 * And, IPA driver will send back to WLAN host driver
3980 * through exception pipe with fw_desc field set by FW.
3981 * Here we are checking fw_desc field for FORWARD bit
3982 * set, and forward to Tx. Then copy to kernel stack
3983 * only when DISCARD bit is not set.
3984 */
3985 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003986 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3987 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3988 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003989 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003990 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003991 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003992 "Intra-BSS FWD is disabled-skip forward to Tx");
3993 }
3994
3995 hdd_ipa_send_skb_to_network(skb, adapter);
3996 break;
3997
3998 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303999 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004000 "w2i cb wrong event: 0x%x", evt);
4001 return;
4002 }
4003}
4004
4005/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004006 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4007 * @priv: pointer to private data registered with IPA (we register a
4008 * pointer to the global IPA context)
4009 * @evt: the IPA event which triggered the callback
4010 * @data: data associated with the event
4011 *
4012 * Return: None
4013 */
4014static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
4015 unsigned long data)
4016{
4017 cds_ssr_protect(__func__);
4018 __hdd_ipa_w2i_cb(priv, evt, data);
4019 cds_ssr_unprotect(__func__);
4020}
4021
4022/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004023 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4024 * @skb: packet buffer which was transmitted
4025 *
4026 * Return: None
4027 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304028void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004029{
4030 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park52b2b992016-09-22 15:49:51 -07004031 struct ipa_rx_data *ipa_tx_desc;
4032 struct hdd_ipa_tx_desc *tx_desc;
4033 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004034
Yun Park52b2b992016-09-22 15:49:51 -07004035 if (!qdf_nbuf_ipa_owned_get(skb)) {
4036 dev_kfree_skb_any(skb);
4037 return;
4038 }
4039
4040 /* Get Tx desc pointer from SKB CB */
4041 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4042 tx_desc = hdd_ipa->tx_desc_list + id;
4043 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4044
4045 /* Return Tx Desc to IPA */
4046 ipa_free_skb(ipa_tx_desc);
4047
4048 /* Return to free tx desc list */
4049 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4050 tx_desc->ipa_tx_desc_ptr = NULL;
4051 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4052 hdd_ipa->stats.num_tx_desc_q_cnt--;
4053 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004054
4055 hdd_ipa->stats.num_tx_comp_cnt++;
4056
4057 atomic_dec(&hdd_ipa->tx_ref_cnt);
4058
4059 hdd_ipa_rm_try_release(hdd_ipa);
4060}
4061
4062/**
4063 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4064 * @iface_context: interface-specific IPA context
4065 * @ipa_tx_desc: packet data descriptor
4066 *
4067 * Return: None
4068 */
4069static void hdd_ipa_send_pkt_to_tl(
4070 struct hdd_ipa_iface_context *iface_context,
4071 struct ipa_rx_data *ipa_tx_desc)
4072{
4073 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004074 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304075 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004076 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004077
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304078 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004079 adapter = iface_context->adapter;
4080 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304081 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004082 ipa_free_skb(ipa_tx_desc);
4083 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304084 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004085 hdd_ipa_rm_try_release(hdd_ipa);
4086 return;
4087 }
4088
4089 /*
4090 * During CAC period, data packets shouldn't be sent over the air so
4091 * drop all the packets here
4092 */
4093 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4094 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304095 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004096 iface_context->stats.num_tx_cac_drop++;
4097 hdd_ipa_rm_try_release(hdd_ipa);
4098 return;
4099 }
4100
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004101 ++adapter->stats.tx_packets;
4102
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304103 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004104
4105 skb = ipa_tx_desc->skb;
4106
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304107 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004108
4109 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304110 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004111 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304112 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004113 ipa_tx_desc->dma_addr
4114 + HDD_IPA_WLAN_FRAG_HEADER
4115 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004116 ipa_tx_desc->skb->len -=
4117 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4118 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304119 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004120
Yun Park52b2b992016-09-22 15:49:51 -07004121 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4122 /* get free Tx desc and assign ipa_tx_desc pointer */
4123 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4124 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4125 struct hdd_ipa_tx_desc, link);
4126 list_del(&tx_desc->link);
4127 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4128 hdd_ipa->stats.num_tx_desc_q_cnt++;
4129 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4130 /* Store Tx Desc index into SKB CB */
4131 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4132 } else {
4133 hdd_ipa->stats.num_tx_desc_error++;
4134 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4135 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "No free Tx desc!");
4136 ipa_free_skb(ipa_tx_desc);
4137 hdd_ipa_rm_try_release(hdd_ipa);
4138 return;
4139 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004140
4141 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
4142
Leo Changfdb45c32016-10-28 11:09:23 -07004143 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004144 (struct cdp_vdev *)iface_context->tl_context,
4145 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304147 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
jiad05c1e812017-08-01 16:48:52 +08004148 qdf_nbuf_free(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004149 iface_context->stats.num_tx_err++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004150 return;
4151 }
4152
4153 atomic_inc(&hdd_ipa->tx_ref_cnt);
4154
4155 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004156}
4157
4158/**
Leo Chang11545d62016-10-17 14:53:50 -07004159 * hdd_ipa_is_present() - get IPA hw status
4160 * @hdd_ctx: pointer to hdd context
4161 *
4162 * ipa_uc_reg_rdyCB is not directly designed to check
4163 * ipa hw status. This is an undocumented function which
4164 * has confirmed with IPA team.
4165 *
4166 * Return: true - ipa hw present
4167 * false - ipa hw not present
4168 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004169bool hdd_ipa_is_present(struct hdd_context *hdd_ctx)
Leo Chang11545d62016-10-17 14:53:50 -07004170{
4171 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004172 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004173 return true;
4174 else
4175 return false;
4176}
4177
4178/**
Leo Chang69c39692016-10-12 20:11:12 -07004179 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004180 * @work: pointer to the scheduled work
4181 *
4182 * Called during PM resume to send packets to TL which were queued
4183 * while host was in the process of suspending.
4184 *
4185 * Return: None
4186 */
Leo Chang69c39692016-10-12 20:11:12 -07004187static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004188{
4189 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4190 struct hdd_ipa_priv,
4191 pm_work);
4192 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304193 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004194 uint32_t dequeued = 0;
4195
Leo Chang69c39692016-10-12 20:11:12 -07004196 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4197 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304198 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304199 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4200 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304201 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004202
4203 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004204 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004205 if (pm_tx_cb->exception) {
4206 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4207 "FLUSH EXCEPTION");
4208 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
4209 } else {
4210 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004211 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004212 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304213 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004214 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304215 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004216 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4217 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004218
4219 hdd_ipa->stats.num_tx_dequeued += dequeued;
4220 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4221 hdd_ipa->stats.num_max_pm_queue = dequeued;
4222}
4223
4224/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004225 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004226 * @priv: pointer to private data registered with IPA (we register a
4227 * pointer to the interface-specific IPA context)
4228 * @evt: the IPA event which triggered the callback
4229 * @data: data associated with the event
4230 *
4231 * Return: None
4232 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004233static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004234 unsigned long data)
4235{
4236 struct hdd_ipa_priv *hdd_ipa = NULL;
4237 struct ipa_rx_data *ipa_tx_desc;
4238 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304239 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004240 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304241 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004242
Mukul Sharma81661ae2015-10-30 20:26:02 +05304243 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004244 ipa_tx_desc = (struct ipa_rx_data *)data;
4245 hdd_ipa = iface_context->hdd_ipa;
4246
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004247 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004248 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4249 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004250 iface_context->stats.num_tx_drop++;
4251 return;
4252 }
4253
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 /*
4255 * When SSR is going on or driver is unloading, just drop the packets.
4256 * During SSR, there is no use in queueing the packets as STA has to
4257 * connect back any way
4258 */
4259 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304260 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004261 ipa_free_skb(ipa_tx_desc);
4262 iface_context->stats.num_tx_drop++;
4263 return;
4264 }
4265
4266 skb = ipa_tx_desc->skb;
4267
Yun Parkb187d542016-11-14 18:10:04 -08004268 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4269 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004270
4271 /*
4272 * If PROD resource is not requested here then there may be cases where
4273 * IPA hardware may be clocked down because of not having proper
4274 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4275 * workaround to request PROD resource while data is going over CONS
4276 * pipe to prevent the IPA hardware clockdown.
4277 */
4278 hdd_ipa_rm_request(hdd_ipa);
4279
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304280 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004281 /*
4282 * If host is still suspended then queue the packets and these will be
4283 * drained later when resume completes. When packet is arrived here and
4284 * host is suspended, this means that there is already resume is in
4285 * progress.
4286 */
4287 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304288 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004289 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4290 pm_tx_cb->iface_context = iface_context;
4291 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304292 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293 hdd_ipa->stats.num_tx_queued++;
4294
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304295 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004296 return;
4297 }
4298
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304299 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004300
4301 /*
4302 * If we are here means, host is not suspended, wait for the work queue
4303 * to finish.
4304 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004305 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004306
4307 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4308}
4309
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004310/*
4311 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4312 * @priv: pointer to private data registered with IPA (we register a
4313 * pointer to the interface-specific IPA context)
4314 * @evt: the IPA event which triggered the callback
4315 * @data: data associated with the event
4316 *
4317 * Return: None
4318 */
4319static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
4320 unsigned long data)
4321{
4322 cds_ssr_protect(__func__);
4323 __hdd_ipa_i2w_cb(priv, evt, data);
4324 cds_ssr_unprotect(__func__);
4325}
4326
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004327/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004328 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004329 * @hdd_ctx: Global HDD context
4330 *
4331 * Return: 0 on success, negativer errno on error
4332 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004333static int __hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004335 struct hdd_ipa_priv *hdd_ipa;
4336
4337 if (wlan_hdd_validate_context(hdd_ctx))
4338 return 0;
4339
4340 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004341
4342 if (!hdd_ipa_is_enabled(hdd_ctx))
4343 return 0;
4344
4345 /*
4346 * Check if IPA is ready for suspend, If we are here means, there is
4347 * high chance that suspend would go through but just to avoid any race
4348 * condition after suspend started, these checks are conducted before
4349 * allowing to suspend.
4350 */
4351 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4352 return -EAGAIN;
4353
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304354 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355
4356 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304357 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004358 return -EAGAIN;
4359 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304360 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004361
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304362 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304364 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004365
4366 return 0;
4367}
4368
4369/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004370 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4371 * @hdd_ctx: Global HDD context
4372 *
4373 * Return: 0 on success, negativer errno on error
4374 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004375int hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004376{
4377 int ret;
4378
4379 cds_ssr_protect(__func__);
4380 ret = __hdd_ipa_suspend(hdd_ctx);
4381 cds_ssr_unprotect(__func__);
4382
4383 return ret;
4384}
4385
4386/**
4387 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004388 * hdd_ctx: Global HDD context
4389 *
4390 * Return: 0 on success, negative errno on error
4391 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004392static int __hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004393{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004394 struct hdd_ipa_priv *hdd_ipa;
4395
4396 if (wlan_hdd_validate_context(hdd_ctx))
4397 return 0;
4398
4399 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004400
4401 if (!hdd_ipa_is_enabled(hdd_ctx))
4402 return 0;
4403
4404 schedule_work(&hdd_ipa->pm_work);
4405
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304406 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004407 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304408 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004409
4410 return 0;
4411}
4412
4413/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004414 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4415 * hdd_ctx: Global HDD context
4416 *
4417 * Return: 0 on success, negative errno on error
4418 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004419int hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004420{
4421 int ret;
4422
4423 cds_ssr_protect(__func__);
4424 ret = __hdd_ipa_resume(hdd_ctx);
4425 cds_ssr_unprotect(__func__);
4426
4427 return ret;
4428}
4429
4430/**
Yun Park52b2b992016-09-22 15:49:51 -07004431 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
4432 * @hdd_ipa: Global HDD IPA context
4433 *
4434 * Return: 0 on success, negative errno on error
4435 */
4436static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
4437{
4438 int i;
4439 uint32_t max_desc_cnt;
4440 struct hdd_ipa_tx_desc *tmp_desc;
jiad14fe4fb2017-08-08 13:33:14 +08004441 struct ol_txrx_pdev_t *pdev;
Yun Park52b2b992016-09-22 15:49:51 -07004442
jiad14fe4fb2017-08-08 13:33:14 +08004443 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
4444 if (!pdev) {
4445 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "pdev is NULL");
4446 return -ENODEV;
4447 }
4448
4449 hdd_ipa->tx_desc_size = QDF_MIN(
4450 hdd_ipa->hdd_ctx->config->IpaMccTxDescSize,
4451 pdev->tx_desc.pool_size);
Yun Park52b2b992016-09-22 15:49:51 -07004452
4453 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
4454
jiad14fe4fb2017-08-08 13:33:14 +08004455 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc) *
4456 hdd_ipa->tx_desc_size);
Yun Park52b2b992016-09-22 15:49:51 -07004457
4458 if (!tmp_desc) {
4459 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4460 "Free Tx descriptor allocation failed");
4461 return -ENOMEM;
4462 }
4463
4464 hdd_ipa->tx_desc_list = tmp_desc;
4465
4466 qdf_spin_lock_bh(&hdd_ipa->q_lock);
jiad14fe4fb2017-08-08 13:33:14 +08004467 for (i = 0; i < hdd_ipa->tx_desc_size; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07004468 tmp_desc->id = i;
4469 tmp_desc->ipa_tx_desc_ptr = NULL;
4470 list_add_tail(&tmp_desc->link,
4471 &hdd_ipa->free_tx_desc_head);
4472 tmp_desc++;
4473 }
4474
4475 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4476 hdd_ipa->stats.num_tx_desc_error = 0;
4477
4478 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4479
4480 return 0;
4481}
4482
4483/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4485 * @hdd_ipa: Global HDD IPA context
4486 *
4487 * Return: 0 on success, negative errno on error
4488 */
4489static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4490{
4491 int i, ret = 0;
4492 struct ipa_sys_connect_params *ipa;
4493 uint32_t desc_fifo_sz;
4494
4495 /* The maximum number of descriptors that can be provided to a BAM at
4496 * once is one less than the total number of descriptors that the buffer
4497 * can contain.
4498 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4499 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4500 * be provided at once.
4501 * Because of above requirement, one extra descriptor will be added to
4502 * make sure hardware always has one descriptor.
4503 */
4504 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4505 + sizeof(struct sps_iovec);
4506
4507 /*setup TX pipes */
4508 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4509 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4510
4511 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4512 ipa->desc_fifo_sz = desc_fifo_sz;
4513 ipa->priv = &hdd_ipa->iface_context[i];
4514 ipa->notify = hdd_ipa_i2w_cb;
4515
4516 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4517 ipa->ipa_ep_cfg.hdr.hdr_len =
4518 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4519 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4520 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4521 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4522 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4523 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4524 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4525 } else {
4526 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4527 }
4528 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4529
4530 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4531 ipa->keep_ipa_awake = 1;
4532
4533 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4534 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004535 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4536 "Failed for pipe %d ret: %d", i, ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004537 goto setup_sys_pipe_fail;
4538 }
4539 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4540 }
4541
4542 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4543 /*
4544 * Hard code it here, this can be extended if in case
4545 * PROD pipe is also per interface.
4546 * Right now there is no advantage of doing this.
4547 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004548 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4549
Yun Parkb4f591d2017-03-29 15:51:01 -07004550 ipa->client = IPA_CLIENT_WLAN1_PROD;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004551
4552 ipa->desc_fifo_sz = desc_fifo_sz;
4553 ipa->priv = hdd_ipa;
4554 ipa->notify = hdd_ipa_w2i_cb;
4555
4556 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4557 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4558 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4559 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4560
4561 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4562 ipa->keep_ipa_awake = 1;
4563
4564 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4565 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304566 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004567 "Failed for RX pipe: %d", ret);
4568 goto setup_sys_pipe_fail;
4569 }
4570 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4571 }
4572
jiad14fe4fb2017-08-08 13:33:14 +08004573 /* Allocate free Tx desc list */
Yun Park52b2b992016-09-22 15:49:51 -07004574 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
4575 if (ret)
4576 goto setup_sys_pipe_fail;
4577
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004578 return ret;
4579
4580setup_sys_pipe_fail:
4581
4582 while (--i >= 0) {
4583 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304584 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004585 sizeof(struct hdd_ipa_sys_pipe));
4586 }
4587
4588 return ret;
4589}
4590
4591/**
4592 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4593 * @hdd_ipa: Global HDD IPA context
4594 *
4595 * Return: None
4596 */
4597static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4598{
4599 int ret = 0, i;
Yun Park52b2b992016-09-22 15:49:51 -07004600 struct hdd_ipa_tx_desc *tmp_desc;
4601 struct ipa_rx_data *ipa_tx_desc;
4602
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004603 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4604 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
Yun Parkb4f591d2017-03-29 15:51:01 -07004605 ret = ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4606 conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004607 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304608 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004609 ret);
4610
4611 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4612 }
4613 }
Yun Park52b2b992016-09-22 15:49:51 -07004614
4615 if (hdd_ipa->tx_desc_list) {
Yun Park52b2b992016-09-22 15:49:51 -07004616 qdf_spin_lock_bh(&hdd_ipa->q_lock);
jiad14fe4fb2017-08-08 13:33:14 +08004617 for (i = 0; i < hdd_ipa->tx_desc_size; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07004618 tmp_desc = hdd_ipa->tx_desc_list + i;
4619 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
4620 if (ipa_tx_desc)
4621 ipa_free_skb(ipa_tx_desc);
4622 }
4623 tmp_desc = hdd_ipa->tx_desc_list;
4624 hdd_ipa->tx_desc_list = NULL;
4625 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4626 hdd_ipa->stats.num_tx_desc_error = 0;
4627 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4628 qdf_mem_free(tmp_desc);
4629 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004630}
4631
4632/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004633 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4634 * @iface_context: interface-specific IPA context
4635 *
4636 * Return: None
4637 */
4638static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4639{
4640 if (iface_context == NULL)
4641 return;
4642
Yun Parkb4f591d2017-03-29 15:51:01 -07004643 cdp_ipa_cleanup_iface(cds_get_context(QDF_MODULE_ID_SOC),
4644 iface_context->adapter->dev->name,
4645 hdd_ipa_is_ipv6_enabled(iface_context->hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004646
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304647 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004648 iface_context->adapter->ipa_context = NULL;
4649 iface_context->adapter = NULL;
4650 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304651 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004652 iface_context->ifa_address = 0;
4653 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304654 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004655 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304656 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004657 }
4658 iface_context->hdd_ipa->num_iface--;
4659}
4660
4661/**
4662 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4663 * @hdd_ipa: HDD IPA global context
4664 * @adapter: Interface upon which IPA is being setup
4665 * @sta_id: Station ID of the API instance
4666 *
4667 * Return: 0 on success, negative errno value on error
4668 */
4669static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
4670 hdd_adapter_t *adapter, uint8_t sta_id)
4671{
4672 struct hdd_ipa_iface_context *iface_context = NULL;
4673 void *tl_context = NULL;
4674 int i, ret = 0;
4675
4676 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4677 * channel change indication. Since these indications are sent by lower
4678 * layer as SAP updates and IPA doesn't have to do anything for these
4679 * updates so ignoring!
4680 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004681 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004682 return 0;
4683
4684 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4685 if (hdd_ipa->iface_context[i].adapter == NULL) {
4686 iface_context = &(hdd_ipa->iface_context[i]);
4687 break;
4688 }
4689 }
4690
4691 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304692 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004693 "All the IPA interfaces are in use");
4694 ret = -ENOMEM;
4695 goto end;
4696 }
4697
4698 adapter->ipa_context = iface_context;
4699 iface_context->adapter = adapter;
4700 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004701 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07004702 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004703 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304704 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004705 "Not able to get TL context sta_id: %d", sta_id);
4706 ret = -EINVAL;
4707 goto end;
4708 }
4709
4710 iface_context->tl_context = tl_context;
4711
Yun Parkb4f591d2017-03-29 15:51:01 -07004712 ret = cdp_ipa_setup_iface(cds_get_context(QDF_MODULE_ID_SOC),
4713 adapter->dev->name, adapter->dev->dev_addr,
4714 iface_context->prod_client,
4715 iface_context->cons_client,
4716 adapter->sessionId,
4717 hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004718 if (ret)
4719 goto end;
4720
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004721 hdd_ipa->num_iface++;
4722 return ret;
4723
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004724end:
4725 if (iface_context)
4726 hdd_ipa_cleanup_iface(iface_context);
4727 return ret;
4728}
4729
Yun Parka27049a2016-10-11 12:30:49 -07004730#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004731/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004732 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004733 * @mcc_mode: 0=MCC/1=SCC
4734 *
4735 * Return: 0 on success, negative errno value on error
4736 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004737static int __hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004738{
4739 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304740 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004741 hdd_adapter_t *pAdapter;
4742 struct ipa_msg_meta meta;
4743 struct ipa_wlan_msg *msg;
4744 int ret;
4745
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004746 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004747 return -EINVAL;
4748
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004749 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4750 return -EINVAL;
4751
4752 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004753 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004754 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304755 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004756 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08004757 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004758 pAdapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004759 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004760 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004761 hdd_deinit_tx_rx(pAdapter);
4762 }
4763 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004764 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004765 adapter_node = next;
4766 }
4767 }
4768
4769 /* Send SCC/MCC Switching event to IPA */
4770 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304771 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004772 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004773 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004774 return -ENOMEM;
4775 }
4776
4777 meta.msg_type = mcc_mode ?
4778 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Srinivas Girigowda97852372017-03-06 16:52:59 -08004779 hdd_debug("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004780
4781 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4782
4783 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004784 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004785 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304786 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004787 }
4788
4789 return ret;
4790}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004791
4792/**
4793 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4794 * @mcc_mode: 0=MCC/1=SCC
4795 *
4796 * Return: 0 on success, negative errno value on error
4797 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004798int hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx, bool mcc_mode)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004799{
4800 int ret;
4801
4802 cds_ssr_protect(__func__);
4803 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4804 cds_ssr_unprotect(__func__);
4805
4806 return ret;
4807}
Yun Parka27049a2016-10-11 12:30:49 -07004808#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004809
4810/**
4811 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4812 * @event: IPA WLAN event to be converted to a string
4813 *
4814 * Return: ASCII string representing the IPA WLAN event
4815 */
4816static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4817{
4818 switch (event) {
4819 case WLAN_CLIENT_CONNECT:
4820 return "WLAN_CLIENT_CONNECT";
4821 case WLAN_CLIENT_DISCONNECT:
4822 return "WLAN_CLIENT_DISCONNECT";
4823 case WLAN_CLIENT_POWER_SAVE_MODE:
4824 return "WLAN_CLIENT_POWER_SAVE_MODE";
4825 case WLAN_CLIENT_NORMAL_MODE:
4826 return "WLAN_CLIENT_NORMAL_MODE";
4827 case SW_ROUTING_ENABLE:
4828 return "SW_ROUTING_ENABLE";
4829 case SW_ROUTING_DISABLE:
4830 return "SW_ROUTING_DISABLE";
4831 case WLAN_AP_CONNECT:
4832 return "WLAN_AP_CONNECT";
4833 case WLAN_AP_DISCONNECT:
4834 return "WLAN_AP_DISCONNECT";
4835 case WLAN_STA_CONNECT:
4836 return "WLAN_STA_CONNECT";
4837 case WLAN_STA_DISCONNECT:
4838 return "WLAN_STA_DISCONNECT";
4839 case WLAN_CLIENT_CONNECT_EX:
4840 return "WLAN_CLIENT_CONNECT_EX";
4841
4842 case IPA_WLAN_EVENT_MAX:
4843 default:
4844 return "UNKNOWN";
4845 }
4846}
4847
4848/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004849 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4850 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4851 *
4852 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4853 */
4854static enum ipa_wlan_event
4855hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4856{
4857 enum ipa_wlan_event ipa_event;
4858
4859 switch (hdd_ipa_event_type) {
4860 case HDD_IPA_CLIENT_CONNECT:
4861 ipa_event = WLAN_CLIENT_CONNECT;
4862 break;
4863 case HDD_IPA_CLIENT_DISCONNECT:
4864 ipa_event = WLAN_CLIENT_DISCONNECT;
4865 break;
4866 case HDD_IPA_AP_CONNECT:
4867 ipa_event = WLAN_AP_CONNECT;
4868 break;
4869 case HDD_IPA_AP_DISCONNECT:
4870 ipa_event = WLAN_AP_DISCONNECT;
4871 break;
4872 case HDD_IPA_STA_CONNECT:
4873 ipa_event = WLAN_STA_CONNECT;
4874 break;
4875 case HDD_IPA_STA_DISCONNECT:
4876 ipa_event = WLAN_STA_DISCONNECT;
4877 break;
4878 case HDD_IPA_CLIENT_CONNECT_EX:
4879 ipa_event = WLAN_CLIENT_CONNECT_EX;
4880 break;
4881 case HDD_IPA_WLAN_EVENT_MAX:
4882 default:
4883 ipa_event = IPA_WLAN_EVENT_MAX;
4884 break;
4885 }
4886 return ipa_event;
4887
4888}
4889
4890/**
4891 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004892 * @adapter: adapter upon which the event was received
4893 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004894 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004895 * @mac_address: MAC address associated with the event
4896 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004897 * This function is meant to be called from within wlan_hdd_ipa.c
4898 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004899 * Return: 0 on success, negative errno value on error
4900 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07004901static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004902 enum ipa_wlan_event type, uint8_t *mac_addr)
4903{
4904 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4905 struct ipa_msg_meta meta;
4906 struct ipa_wlan_msg *msg;
4907 struct ipa_wlan_msg_ex *msg_ex = NULL;
4908 int ret;
4909
Srinivas Girigowda97852372017-03-06 16:52:59 -08004910 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004911 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
4912 mac_addr, sta_id);
4913
4914 if (type >= IPA_WLAN_EVENT_MAX)
4915 return -EINVAL;
4916
4917 if (WARN_ON(is_zero_ether_addr(mac_addr)))
4918 return -EINVAL;
4919
4920 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304921 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004922 return -EINVAL;
4923 }
4924
4925 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
4926 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08004927 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004928 return 0;
4929 }
4930
4931 /*
4932 * During IPA UC resource loading/unloading new events can be issued.
4933 * Store the events separately and handle them later.
4934 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004935 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4936 if (hdd_ipa->resource_loading) {
4937 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004938 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08004939
Yun Park64c405e2017-01-10 22:35:51 -08004940 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4941 "IPA resource load in progress");
Yun Park7c4f31b2016-11-30 10:09:21 -08004942
Yun Park64c405e2017-01-10 22:35:51 -08004943 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004944
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004945 pending_event_count =
4946 qdf_list_size(&hdd_ipa->pending_event);
4947 if (pending_event_count >=
4948 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004949 hdd_debug("Reached max pending event count");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004950 qdf_list_remove_front(&hdd_ipa->pending_event,
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004951 (qdf_list_node_t **)&pending_event);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004952 } else {
4953 pending_event =
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004954 qdf_mem_malloc(sizeof(*pending_event));
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004955 }
4956
4957 if (!pending_event) {
Yun Park64c405e2017-01-10 22:35:51 -08004958 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park7c4f31b2016-11-30 10:09:21 -08004959 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4960 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004961 return -ENOMEM;
4962 }
4963
4964 pending_event->adapter = adapter;
4965 pending_event->sta_id = sta_id;
4966 pending_event->type = type;
4967 qdf_mem_copy(pending_event->mac_addr,
4968 mac_addr,
4969 QDF_MAC_ADDR_SIZE);
4970 qdf_list_insert_back(&hdd_ipa->pending_event,
4971 &pending_event->node);
4972
Yun Park64c405e2017-01-10 22:35:51 -08004973 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004974 return 0;
4975 } else if (hdd_ipa->resource_unloading) {
Yun Park64c405e2017-01-10 22:35:51 -08004976 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4977 "IPA resource unload in progress");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004978 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004979 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004980 }
4981
4982 hdd_ipa->stats.event[type]++;
4983
Leo Chang3bc8fed2015-11-13 10:59:47 -08004984 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004985 switch (type) {
4986 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004987 qdf_mutex_acquire(&hdd_ipa->event_lock);
4988
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004989 /* STA already connected and without disconnect, connect again
4990 * This is Roaming scenario
4991 */
4992 if (hdd_ipa->sta_connected)
4993 hdd_ipa_cleanup_iface(adapter->ipa_context);
4994
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004995 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4996 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304997 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004998 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004999 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005000
Yun Park8f289c82016-10-18 16:38:21 -07005001 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5002 (hdd_ipa->sap_num_connected_sta > 0) &&
5003 !hdd_ipa->sta_connected) {
5004 qdf_mutex_release(&hdd_ipa->event_lock);
5005 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005006 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005007 qdf_mutex_acquire(&hdd_ipa->event_lock);
5008 }
5009
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005010 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005011 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005012 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005013
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005014 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005015
5016 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005017 break;
5018
5019 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005020 qdf_mutex_acquire(&hdd_ipa->event_lock);
5021
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005022 /* For DFS channel we get two start_bss event (before and after
5023 * CAC). Also when ACS range includes both DFS and non DFS
5024 * channels, we could possibly change channel many times due to
5025 * RADAR detection and chosen channel may not be a DFS channels.
5026 * So dont return error here. Just discard the event.
5027 */
Yun Park8f289c82016-10-18 16:38:21 -07005028 if (adapter->ipa_context) {
5029 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005030 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005031 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005032
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005033 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5034 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005035 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005036 hdd_err("%s: Evt: %d, Interface setup failed",
5037 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005038 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005039 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005040
Yun Park8f289c82016-10-18 16:38:21 -07005041 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5042 qdf_mutex_release(&hdd_ipa->event_lock);
5043 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005044 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005045 qdf_mutex_acquire(&hdd_ipa->event_lock);
5046 }
5047
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005048 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005049 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005050 (adapter->ipa_context))->iface_id;
5051
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305052 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005053 break;
5054
5055 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305056 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005057
5058 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005059 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005060 hdd_err("%s: Evt: %d, STA already disconnected",
5061 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005062 return -EINVAL;
5063 }
Yun Parka37592b2016-06-11 17:10:28 -07005064
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005065 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005066
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005067 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005068 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005069 msg_ex->name);
5070 } else {
5071 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005072 if (!hdd_ipa->num_iface &&
5073 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305074 hdd_ipa->activated_fw_pipe) &&
5075 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005076 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005077 }
5078
Yun Park74127cf2016-09-18 11:22:41 -07005079 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5080 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005081 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005082 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005083 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005084 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005085 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5086 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005087 }
5088
Yun Park8f289c82016-10-18 16:38:21 -07005089 hdd_ipa_cleanup_iface(adapter->ipa_context);
5090
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305091 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005092 break;
5093
5094 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005095 qdf_mutex_acquire(&hdd_ipa->event_lock);
5096
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005097 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005098 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005099 hdd_err("%s: Evt: %d, SAP already disconnected",
5100 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005101 return -EINVAL;
5102 }
5103
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005104 if ((!hdd_ipa->num_iface) &&
5105 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305106 hdd_ipa->activated_fw_pipe) &&
5107 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005108 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005109 /*
5110 * We disable WDI pipes directly here since
5111 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5112 * processed when unloading WLAN driver is in
5113 * progress
5114 */
5115 hdd_ipa_uc_disable_pipes(hdd_ipa);
5116 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305117 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005118 "NO INTF left but still pipe clean up");
5119 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5120 }
5121 }
5122
5123 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005124 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005125 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005126 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005127 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005128 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5129 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005130 }
Yun Parka37592b2016-06-11 17:10:28 -07005131
Yun Park8f289c82016-10-18 16:38:21 -07005132 hdd_ipa_cleanup_iface(adapter->ipa_context);
5133
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305134 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005135 break;
5136
5137 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005138 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005139 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005140 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305141 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005142 return 0;
5143 }
5144
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305145 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005146 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5147 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005148 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305149 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005150 "%s: STA ID %d found, not valid",
5151 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005152 return 0;
5153 }
Yun Park312f71a2015-12-08 10:22:42 -08005154
5155 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005156 if (hdd_ipa->sap_num_connected_sta == 0 &&
5157 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005158 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005159 hdd_ipa->sta_connected) {
5160 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005161 hdd_ipa_uc_offload_enable_disable(
5162 hdd_get_adapter(hdd_ipa->hdd_ctx,
5163 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005164 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005165 qdf_mutex_acquire(&hdd_ipa->event_lock);
5166 }
Yun Parka37592b2016-06-11 17:10:28 -07005167
Yun Park312f71a2015-12-08 10:22:42 -08005168 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5169 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305170 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005171 "%s: handle 1st con ret %d",
5172 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005173
5174 if (hdd_ipa_uc_sta_is_enabled(
5175 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005176 hdd_ipa->sta_connected) {
5177 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005178 hdd_ipa_uc_offload_enable_disable(
5179 hdd_get_adapter(
5180 hdd_ipa->hdd_ctx,
5181 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005182 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005183 } else {
5184 qdf_mutex_release(&hdd_ipa->event_lock);
5185 }
Yun Parka37592b2016-06-11 17:10:28 -07005186
Yun Park312f71a2015-12-08 10:22:42 -08005187 return ret;
5188 }
5189 }
5190
5191 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005192
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305193 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005194
5195 meta.msg_type = type;
5196 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5197 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305198 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005199
5200 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305201 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005202 "msg_ex allocation failed");
5203 return -ENOMEM;
5204 }
5205 strlcpy(msg_ex->name, adapter->dev->name,
5206 IPA_RESOURCE_NAME_MAX);
5207 msg_ex->num_of_attribs = 1;
5208 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5209 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5210 msg_ex->attribs[0].offset =
5211 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5212 } else {
5213 msg_ex->attribs[0].offset =
5214 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5215 }
5216 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5217 IPA_MAC_ADDR_SIZE);
5218
5219 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5220
5221 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005222 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305223 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305224 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005225 return ret;
5226 }
5227 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005228 return ret;
5229
5230 case WLAN_CLIENT_DISCONNECT:
5231 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005232 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005233 "%s: IPA UC OFFLOAD NOT ENABLED",
5234 msg_ex->name);
5235 return 0;
5236 }
5237
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305238 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005239 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005240 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305241 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005242 "%s: STA ID %d NOT found, not valid",
5243 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005244 return 0;
5245 }
5246 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005247
Yun Park9b5030f2016-11-08 12:02:37 -08005248 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005249 if (!hdd_ipa->sap_num_connected_sta &&
5250 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005251 if ((false == hdd_ipa->resource_unloading)
5252 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305253 hdd_ipa->activated_fw_pipe) &&
5254 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005255 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5256 }
5257
Yun Park9b5030f2016-11-08 12:02:37 -08005258 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jiad9d472c92017-07-28 14:05:31 +08005259 hdd_ipa->sta_connected) {
5260 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005261 hdd_ipa_uc_offload_enable_disable(
5262 hdd_get_adapter(hdd_ipa->hdd_ctx,
5263 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005264 SIR_STA_RX_DATA_OFFLOAD, false);
jiad9d472c92017-07-28 14:05:31 +08005265 } else {
5266 qdf_mutex_release(&hdd_ipa->event_lock);
5267 }
Yun Park8f289c82016-10-18 16:38:21 -07005268 } else {
5269 qdf_mutex_release(&hdd_ipa->event_lock);
5270 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005271 break;
5272
5273 default:
5274 return 0;
5275 }
5276
5277 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305278 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005279 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305280 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005281 return -ENOMEM;
5282 }
5283
5284 meta.msg_type = type;
5285 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5286 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5287
Srinivas Girigowda97852372017-03-06 16:52:59 -08005288 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005289 msg->name, meta.msg_type);
5290
5291 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5292
5293 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005294 hdd_err("%s: Evt: %d fail:%d",
5295 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305296 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005297 return ret;
5298 }
5299
5300 hdd_ipa->stats.num_send_msg++;
5301
5302end:
5303 return ret;
5304}
5305
5306/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005307 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005308 * @adapter: adapter upon which the event was received
5309 * @sta_id: station id for the event
5310 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5311 * @mac_address: MAC address associated with the event
5312 *
5313 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5314 *
5315 * Return: 0 on success, negative errno value on error
5316 */
5317int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
5318 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5319{
5320 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005321 int ret = 0;
5322
5323 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005324
Leo Changa202b522016-10-14 16:13:50 -07005325 /* Data path offload only support for STA and SAP mode */
5326 if ((QDF_STA_MODE == adapter->device_mode) ||
5327 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005328 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005329
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005330 cds_ssr_unprotect(__func__);
5331
5332 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005333}
5334
5335/**
5336 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5337 * @hdd_ipa: Global HDD IPA context
5338 *
5339 * Return: None
5340 */
5341static void
5342hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5343{
5344 unsigned int pending_event_count;
5345 struct ipa_uc_pending_event *pending_event = NULL;
5346
5347 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005348 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005349 "%s, Pending Event Count %d", __func__, pending_event_count);
5350 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005351 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005352 "%s, No Pending Event", __func__);
5353 return;
5354 }
5355
5356 qdf_list_remove_front(&hdd_ipa->pending_event,
5357 (qdf_list_node_t **)&pending_event);
5358 while (pending_event != NULL) {
5359 __hdd_ipa_wlan_evt(pending_event->adapter,
5360 pending_event->type,
5361 pending_event->sta_id,
5362 pending_event->mac_addr);
5363 qdf_mem_free(pending_event);
5364 pending_event = NULL;
5365 qdf_list_remove_front(&hdd_ipa->pending_event,
5366 (qdf_list_node_t **)&pending_event);
5367 }
5368}
5369
5370/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005371 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5372 * @state: IPA RM state value
5373 *
5374 * Return: ASCII string representing the IPA RM state
5375 */
5376static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5377{
5378 switch (state) {
5379 case HDD_IPA_RM_RELEASED:
5380 return "RELEASED";
5381 case HDD_IPA_RM_GRANT_PENDING:
5382 return "GRANT_PENDING";
5383 case HDD_IPA_RM_GRANTED:
5384 return "GRANTED";
5385 }
5386
5387 return "UNKNOWN";
5388}
5389
5390/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005391 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005392 * @hdd_ctx: HDD global context
5393 *
5394 * Allocate hdd_ipa resources, ipa pipe resource and register
5395 * wlan interface with IPA module.
5396 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305397 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005398 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005399static QDF_STATUS __hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005400{
5401 struct hdd_ipa_priv *hdd_ipa = NULL;
5402 int ret, i;
5403 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005404 struct ol_txrx_pdev_t *pdev = NULL;
Yun Park66f24c42017-03-20 10:39:47 -07005405 struct ipa_rm_perf_profile profile;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005406
5407 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305408 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005409
Yun Parkbaa62862017-01-18 13:43:34 -08005410 ENTER();
5411
5412 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005413 if (!pdev) {
5414 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5415 goto fail_return;
5416 }
5417
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305418 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005419 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305420 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005421 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005422 }
5423
5424 hdd_ctx->hdd_ipa = hdd_ipa;
5425 ghdd_ipa = hdd_ipa;
5426 hdd_ipa->hdd_ctx = hdd_ctx;
5427 hdd_ipa->num_iface = 0;
5428
5429 /* Create the interface context */
5430 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5431 iface_context = &hdd_ipa->iface_context[i];
5432 iface_context->hdd_ipa = hdd_ipa;
5433 iface_context->cons_client =
5434 hdd_ipa_adapter_2_client[i].cons_client;
5435 iface_context->prod_client =
5436 hdd_ipa_adapter_2_client[i].prod_client;
5437 iface_context->iface_id = i;
5438 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305439 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005440 }
5441 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005442 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5443 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005444 }
5445
Leo Chang69c39692016-10-12 20:11:12 -07005446 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305447 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07005448 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305449 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005450 qdf_list_create(&hdd_ipa->pending_event, 1000);
5451 qdf_mutex_create(&hdd_ipa->event_lock);
5452 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005453
5454 ret = hdd_ipa_setup_rm(hdd_ipa);
5455 if (ret)
5456 goto fail_setup_rm;
5457
5458 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5459 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305460 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005461 hdd_ipa->sap_num_connected_sta = 0;
5462 hdd_ipa->ipa_tx_packets_diff = 0;
5463 hdd_ipa->ipa_rx_packets_diff = 0;
5464 hdd_ipa->ipa_p_tx_packets = 0;
5465 hdd_ipa->ipa_p_rx_packets = 0;
5466 hdd_ipa->resource_loading = false;
5467 hdd_ipa->resource_unloading = false;
5468 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005469 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08005470 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005471 /* Setup IPA sys_pipe for MCC */
5472 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5473 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5474 if (ret)
5475 goto fail_create_sys_pipe;
5476 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005477 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5478 goto fail_create_sys_pipe;
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005479
5480 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5481 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
5482 hdd_ipa_uc_fw_op_event_handler);
5483 hdd_ipa->uc_op_work[i].msg = NULL;
5484 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005485 } else {
5486 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5487 if (ret)
5488 goto fail_create_sys_pipe;
5489 }
5490
Yun Park66f24c42017-03-20 10:39:47 -07005491 /* When IPA clock scaling is disabled, initialze maximum clock */
5492 if (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)) {
5493 profile.max_supported_bandwidth_mbps = 800;
5494 hdd_debug("IPA clock scaling is disabled.");
5495 hdd_debug("Set initial CONS/PROD perf: %d",
5496 profile.max_supported_bandwidth_mbps);
5497 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
5498 &profile);
5499 if (ret) {
5500 hdd_err("RM CONS set perf profile failed: %d", ret);
5501 goto fail_create_sys_pipe;
5502 }
5503
5504 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
5505 &profile);
5506 if (ret) {
5507 hdd_err("RM PROD set perf profile failed: %d", ret);
5508 goto fail_create_sys_pipe;
5509 }
5510 }
5511
Yun Parkbaa62862017-01-18 13:43:34 -08005512 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305513 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005514
5515fail_create_sys_pipe:
5516 hdd_ipa_destroy_rm_resource(hdd_ipa);
5517fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305518 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305519 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005520 hdd_ctx->hdd_ipa = NULL;
5521 ghdd_ipa = NULL;
5522fail_return:
Yun Parkbaa62862017-01-18 13:43:34 -08005523 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305524 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005525}
5526
5527/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005528 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5529 * @hdd_ctx: HDD global context
5530 *
5531 * Allocate hdd_ipa resources, ipa pipe resource and register
5532 * wlan interface with IPA module.
5533 *
5534 * Return: QDF_STATUS enumeration
5535 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005536QDF_STATUS hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005537{
5538 QDF_STATUS ret;
5539
5540 cds_ssr_protect(__func__);
5541 ret = __hdd_ipa_init(hdd_ctx);
5542 cds_ssr_unprotect(__func__);
5543
5544 return ret;
5545}
5546
Arun Khandavallicc544b32017-01-30 19:52:16 +05305547
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005548/**
Yun Parkf19e07d2015-11-20 11:34:27 -08005549 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
5550 * @hdd_ipa: pointer to HDD IPA struct
5551 *
5552 * Return: none
5553 */
Jeff Johnsond7720632016-10-05 16:04:32 -07005554static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08005555{
5556 struct ipa_uc_pending_event *pending_event = NULL;
5557
Anurag Chouhanffb21542016-02-17 14:33:03 +05305558 while (qdf_list_remove_front(&hdd_ipa->pending_event,
5559 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305560 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005561 }
5562
Anurag Chouhanffb21542016-02-17 14:33:03 +05305563 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005564}
5565
5566/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005567 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005568 * @hdd_ctx: HDD global context
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_cleanup(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005573{
5574 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5575 int i;
5576 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305577 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005578 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5579
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
5583 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5584 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5585 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5586 }
5587
5588 /* Teardown IPA sys_pipe for MCC */
5589 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5590 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5591
5592 hdd_ipa_destroy_rm_resource(hdd_ipa);
5593
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005594 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005595
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305596 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005597
Nirav Shahcbc6d722016-03-01 16:24:53 +05305598 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5599 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305600 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005601
5602 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07005603 if (pm_tx_cb->ipa_tx_desc)
5604 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005605
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305606 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005607 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305608 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005609
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305610 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07005611 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005612
5613 /* destory the interface lock */
5614 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5615 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305616 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005617 }
5618
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005619 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08005620 if (ipa_uc_dereg_rdyCB())
5621 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5622 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005623 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305624 qdf_mutex_destroy(&hdd_ipa->event_lock);
5625 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005626 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005627
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005628 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5629 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5630 hdd_ipa->uc_op_work[i].msg = NULL;
5631 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005632 }
5633
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305634 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005635 hdd_ctx->hdd_ipa = NULL;
5636
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305637 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005638}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005639
5640/**
5641 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5642 * @hdd_ctx: HDD global context
5643 *
5644 * Return: QDF_STATUS enumeration
5645 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005646QDF_STATUS hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005647{
5648 QDF_STATUS ret;
5649
5650 cds_ssr_protect(__func__);
5651 ret = __hdd_ipa_cleanup(hdd_ctx);
5652 cds_ssr_unprotect(__func__);
5653
5654 return ret;
5655}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005656#endif /* IPA_OFFLOAD */