blob: d9fe1f0f8bf022076b55ce411752d6040a620760 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
jge62037862016-12-09 10:44:33 +08002 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ipa.c
30 *
31 * WLAN HDD and ipa interface implementation
32 * Originally written by Qualcomm Atheros, Inc
33 */
34
35#ifdef IPA_OFFLOAD
36
37/* Include Files */
Mohit Khannafa99aea2016-05-12 21:43:13 -070038#include <linux/ipa.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039#include <wlan_hdd_includes.h>
40#include <wlan_hdd_ipa.h>
41
42#include <linux/etherdevice.h>
43#include <linux/atomic.h>
44#include <linux/netdevice.h>
45#include <linux/skbuff.h>
46#include <linux/list.h>
47#include <linux/debugfs.h>
48#include <linux/inetdevice.h>
49#include <linux/ip.h>
50#include <wlan_hdd_softap_tx_rx.h>
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +053051#include <ol_txrx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070052#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053
54#include "cds_sched.h"
55
56#include "wma.h"
57#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080058#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
Dhanashri Atreb08959a2016-03-01 17:28:03 -080060#include "cdp_txrx_ipa.h"
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -080061#include <cdp_txrx_handle.h>
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -080062#include "wlan_policy_mgr_api.h"
63
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080064#define HDD_IPA_DESC_BUFFER_RATIO 4
65#define HDD_IPA_IPV4_NAME_EXT "_ipv4"
66#define HDD_IPA_IPV6_NAME_EXT "_ipv6"
67
68#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
70/* WDI TX and RX PIPE */
71#define HDD_IPA_UC_NUM_WDI_PIPE 2
72#define HDD_IPA_UC_MAX_PENDING_EVENT 33
73
74#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
75#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
76#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
77#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
78
79#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
80#define HDD_IPA_MAX_IFACE 3
81#define HDD_IPA_MAX_SYSBAM_PIPE 4
82#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
83#define HDD_IPA_ENABLE_MASK BIT(0)
84#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
85#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
86#define HDD_IPA_RM_ENABLE_MASK BIT(3)
87#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
88#define HDD_IPA_UC_ENABLE_MASK BIT(5)
89#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
90#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
91
Yun Parkf19e07d2015-11-20 11:34:27 -080092#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
93
tfyu0380a972017-07-13 18:19:37 +080094#define IPA_WLAN_RX_SOFTIRQ_THRESH 16
95
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -070096enum hdd_ipa_uc_op_code {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080097 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
98 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
99 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
100 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
101 HDD_IPA_UC_OPCODE_STATS = 4,
Yun Park637d6482016-10-05 10:51:33 -0700102#ifdef FEATURE_METERING
103 HDD_IPA_UC_OPCODE_SHARING_STATS = 5,
104 HDD_IPA_UC_OPCODE_QUOTA_RSP = 6,
105 HDD_IPA_UC_OPCODE_QUOTA_IND = 7,
106#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800107 HDD_IPA_UC_OPCODE_UC_READY = 8,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800108 /* keep this last */
109 HDD_IPA_UC_OPCODE_MAX
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700110};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800111
112/**
113 * enum - Reason codes for stat query
114 *
115 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
116 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
117 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800118 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800119 */
120enum {
121 HDD_IPA_UC_STAT_REASON_NONE,
122 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -0800123 HDD_IPA_UC_STAT_REASON_BW_CAL,
124 HDD_IPA_UC_STAT_REASON_DUMP_INFO
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800125};
126
127/**
128 * enum hdd_ipa_rm_state - IPA resource manager state
129 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
130 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
131 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
132 */
133enum hdd_ipa_rm_state {
134 HDD_IPA_RM_RELEASED,
135 HDD_IPA_RM_GRANT_PENDING,
136 HDD_IPA_RM_GRANTED,
137};
138
139struct llc_snap_hdr {
140 uint8_t dsap;
141 uint8_t ssap;
142 uint8_t resv[4];
143 __be16 eth_type;
144} __packed;
145
Leo Chang3bc8fed2015-11-13 10:59:47 -0800146/**
147 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
148 * @eth: ether II header
149 * @llc_snap: LLC snap header
150 *
151 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800152struct hdd_ipa_tx_hdr {
153 struct ethhdr eth;
154 struct llc_snap_hdr llc_snap;
155} __packed;
156
Leo Chang3bc8fed2015-11-13 10:59:47 -0800157/**
158 * struct frag_header - fragment header type registered to IPA hardware
159 * @length: fragment length
160 * @reserved1: Reserved not used
161 * @reserved2: Reserved not used
162 *
163 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800165 uint16_t length;
166 uint32_t reserved1;
167 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800168} __packed;
169
Leo Chang3bc8fed2015-11-13 10:59:47 -0800170/**
171 * struct ipa_header - ipa header type registered to IPA hardware
172 * @vdev_id: vdev id
173 * @reserved: Reserved not used
174 *
175 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176struct ipa_header {
177 uint32_t
178 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
179 reserved:24;
180} __packed;
181
Leo Chang3bc8fed2015-11-13 10:59:47 -0800182/**
183 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
184 * @frag_hd: fragment header
185 * @ipa_hd: ipa header
186 * @eth: ether II header
187 *
188 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800189struct hdd_ipa_uc_tx_hdr {
190 struct frag_header frag_hd;
191 struct ipa_header ipa_hd;
192 struct ethhdr eth;
193} __packed;
194
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800195/**
196 * struct hdd_ipa_cld_hdr - IPA CLD Header
197 * @reserved: reserved fields
198 * @iface_id: interface ID
199 * @sta_id: Station ID
200 *
201 * Packed 32-bit structure
202 * +----------+----------+--------------+--------+
203 * | Reserved | QCMAP ID | interface id | STA ID |
204 * +----------+----------+--------------+--------+
205 */
206struct hdd_ipa_cld_hdr {
207 uint8_t reserved[2];
208 uint8_t iface_id;
209 uint8_t sta_id;
210} __packed;
211
212struct hdd_ipa_rx_hdr {
213 struct hdd_ipa_cld_hdr cld_hdr;
214 struct ethhdr eth;
215} __packed;
216
217struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700218 bool exception;
219 hdd_adapter_t *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800220 struct hdd_ipa_iface_context *iface_context;
221 struct ipa_rx_data *ipa_tx_desc;
222};
223
224struct hdd_ipa_uc_rx_hdr {
225 struct ethhdr eth;
226} __packed;
227
228struct hdd_ipa_sys_pipe {
229 uint32_t conn_hdl;
230 uint8_t conn_hdl_valid;
231 struct ipa_sys_connect_params ipa_sys_params;
232};
233
234struct hdd_ipa_iface_stats {
235 uint64_t num_tx;
236 uint64_t num_tx_drop;
237 uint64_t num_tx_err;
238 uint64_t num_tx_cac_drop;
239 uint64_t num_rx_prefilter;
240 uint64_t num_rx_ipa_excep;
241 uint64_t num_rx_recv;
242 uint64_t num_rx_recv_mul;
243 uint64_t num_rx_send_desc_err;
244 uint64_t max_rx_mul;
245};
246
247struct hdd_ipa_priv;
248
249struct hdd_ipa_iface_context {
250 struct hdd_ipa_priv *hdd_ipa;
251 hdd_adapter_t *adapter;
252 void *tl_context;
253
254 enum ipa_client_type cons_client;
255 enum ipa_client_type prod_client;
256
257 uint8_t iface_id; /* This iface ID */
258 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530259 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800260 uint32_t ifa_address;
261 struct hdd_ipa_iface_stats stats;
262};
263
264struct hdd_ipa_stats {
265 uint32_t event[IPA_WLAN_EVENT_MAX];
266 uint64_t num_send_msg;
267 uint64_t num_free_msg;
268
269 uint64_t num_rm_grant;
270 uint64_t num_rm_release;
271 uint64_t num_rm_grant_imm;
272 uint64_t num_cons_perf_req;
273 uint64_t num_prod_perf_req;
274
275 uint64_t num_rx_drop;
276 uint64_t num_rx_ipa_tx_dp;
277 uint64_t num_rx_ipa_splice;
278 uint64_t num_rx_ipa_loop;
279 uint64_t num_rx_ipa_tx_dp_err;
280 uint64_t num_rx_ipa_write_done;
281 uint64_t num_max_ipa_tx_mul;
282 uint64_t num_rx_ipa_hw_maxed_out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800283
Yun Park52b2b992016-09-22 15:49:51 -0700284 uint64_t num_tx_desc_q_cnt;
285 uint64_t num_tx_desc_error;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800286 uint64_t num_tx_comp_cnt;
287 uint64_t num_tx_queued;
288 uint64_t num_tx_dequeued;
289 uint64_t num_max_pm_queue;
290
291 uint64_t num_freeq_empty;
292 uint64_t num_pri_freeq_empty;
293 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800294 uint64_t num_tx_fwd_ok;
295 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800296};
297
298struct ipa_uc_stas_map {
299 bool is_reserved;
300 uint8_t sta_id;
301};
302struct op_msg_type {
303 uint8_t msg_t;
304 uint8_t rsvd;
305 uint16_t op_code;
306 uint16_t len;
307 uint16_t rsvd_snd;
308};
309
310struct ipa_uc_fw_stats {
311 uint32_t tx_comp_ring_base;
312 uint32_t tx_comp_ring_size;
313 uint32_t tx_comp_ring_dbell_addr;
314 uint32_t tx_comp_ring_dbell_ind_val;
315 uint32_t tx_comp_ring_dbell_cached_val;
316 uint32_t tx_pkts_enqueued;
317 uint32_t tx_pkts_completed;
318 uint32_t tx_is_suspend;
319 uint32_t tx_reserved;
320 uint32_t rx_ind_ring_base;
321 uint32_t rx_ind_ring_size;
322 uint32_t rx_ind_ring_dbell_addr;
323 uint32_t rx_ind_ring_dbell_ind_val;
324 uint32_t rx_ind_ring_dbell_ind_cached_val;
325 uint32_t rx_ind_ring_rdidx_addr;
326 uint32_t rx_ind_ring_rd_idx_cached_val;
327 uint32_t rx_refill_idx;
328 uint32_t rx_num_pkts_indicated;
329 uint32_t rx_buf_refilled;
330 uint32_t rx_num_ind_drop_no_space;
331 uint32_t rx_num_ind_drop_no_buf;
332 uint32_t rx_is_suspend;
333 uint32_t rx_reserved;
334};
335
336struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530337 qdf_list_node_t node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800338 hdd_adapter_t *adapter;
339 enum ipa_wlan_event type;
340 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530341 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800342};
343
344/**
345 * struct uc_rm_work_struct
346 * @work: uC RM work
347 * @event: IPA RM event
348 */
349struct uc_rm_work_struct {
350 struct work_struct work;
351 enum ipa_rm_event event;
352};
353
354/**
355 * struct uc_op_work_struct
356 * @work: uC OP work
357 * @msg: OP message
358 */
359struct uc_op_work_struct {
360 struct work_struct work;
361 struct op_msg_type *msg;
362};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800363
364/**
365 * struct uc_rt_debug_info
366 * @time: system time
367 * @ipa_excep_count: IPA exception packet count
368 * @rx_drop_count: IPA Rx drop packet count
369 * @net_sent_count: IPA Rx packet sent to network stack count
370 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800371 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800372 * @tx_fwd_count: IPA Tx forward packet count
373 * @rx_destructor_call: IPA Rx packet destructor count
374 */
375struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530376 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800377 uint64_t ipa_excep_count;
378 uint64_t rx_drop_count;
379 uint64_t net_sent_count;
380 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800381 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800382 uint64_t tx_fwd_count;
383 uint64_t rx_destructor_call;
384};
385
Yun Park637d6482016-10-05 10:51:33 -0700386#ifdef FEATURE_METERING
387struct ipa_uc_sharing_stats {
388 uint64_t ipv4_rx_packets;
389 uint64_t ipv4_rx_bytes;
390 uint64_t ipv6_rx_packets;
391 uint64_t ipv6_rx_bytes;
392 uint64_t ipv4_tx_packets;
393 uint64_t ipv4_tx_bytes;
394 uint64_t ipv6_tx_packets;
395 uint64_t ipv6_tx_bytes;
396};
397
398struct ipa_uc_quota_rsp {
399 uint8_t success;
400 uint8_t reserved[3];
401 uint32_t quota_lo; /* quota limit low bytes */
402 uint32_t quota_hi; /* quota limit high bytes */
403};
404
405struct ipa_uc_quota_ind {
406 uint64_t quota_bytes; /* quota limit in bytes */
407};
408#endif
409
Yun Park52b2b992016-09-22 15:49:51 -0700410/**
411 * struct hdd_ipa_tx_desc
412 * @link: link to list head
413 * @priv: pointer to priv list entry
414 * @id: Tx desc idex
415 * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor
416 */
417struct hdd_ipa_tx_desc {
418 struct list_head link;
419 void *priv;
420 uint32_t id;
421 struct ipa_rx_data *ipa_tx_desc_ptr;
422};
423
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800424struct hdd_ipa_priv {
425 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
426 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
427 uint8_t num_iface;
428 enum hdd_ipa_rm_state rm_state;
429 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530430 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431 * APIs as it is taken care gracefully. Without this, kernel would throw
432 * an warning if spin_lock_bh is used while IRQ is disabled
433 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530434 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800435 struct uc_rm_work_struct uc_rm_work;
436 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530437 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800438 struct delayed_work wake_lock_work;
439 bool wake_lock_released;
440
441 enum ipa_client_type prod_client;
442
443 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530444 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800445 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530446 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800447 bool suspended;
448
Yun Park52b2b992016-09-22 15:49:51 -0700449 qdf_spinlock_t q_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800450
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800451 struct list_head pend_desc_head;
Yun Park52b2b992016-09-22 15:49:51 -0700452 struct hdd_ipa_tx_desc *tx_desc_list;
453 struct list_head free_tx_desc_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800454
455 hdd_context_t *hdd_ctx;
456
457 struct dentry *debugfs_dir;
458 struct hdd_ipa_stats stats;
459
460 struct notifier_block ipv4_notifier;
461 uint32_t curr_prod_bw;
462 uint32_t curr_cons_bw;
463
464 uint8_t activated_fw_pipe;
465 uint8_t sap_num_connected_sta;
466 uint8_t sta_connected;
467 uint32_t tx_pipe_handle;
468 uint32_t rx_pipe_handle;
469 bool resource_loading;
470 bool resource_unloading;
471 bool pending_cons_req;
472 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530473 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530474 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700475 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 uint32_t ipa_tx_packets_diff;
477 uint32_t ipa_rx_packets_diff;
478 uint32_t ipa_p_tx_packets;
479 uint32_t ipa_p_rx_packets;
480 uint32_t stat_req_reason;
481 uint64_t ipa_tx_forward;
482 uint64_t ipa_rx_discard;
483 uint64_t ipa_rx_net_send_count;
484 uint64_t ipa_rx_internel_drop_count;
485 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530486 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800487 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
488 unsigned int rt_buf_fill_index;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800489 struct ipa_wdi_in_params cons_pipe_in;
490 struct ipa_wdi_in_params prod_pipe_in;
491 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800492 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530493 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530494 qdf_mutex_t rt_debug_lock;
495 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800496 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800497 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530498 qdf_dma_addr_t tx_comp_doorbell_paddr;
499 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800500 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
501 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Yun Park637d6482016-10-05 10:51:33 -0700502#ifdef FEATURE_METERING
503 struct ipa_uc_sharing_stats ipa_sharing_stats;
504 struct ipa_uc_quota_rsp ipa_quota_rsp;
505 struct ipa_uc_quota_ind ipa_quota_ind;
506 struct completion ipa_uc_sharing_stats_comp;
507 struct completion ipa_uc_set_quota_comp;
508#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800509};
510
Leo Changcc923e22016-06-16 15:29:03 -0700511#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
512#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800513#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
514#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
515#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
516#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
517#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
518#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700519#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
520 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800521
522#define HDD_IPA_GET_IFACE_ID(_data) \
523 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
524
525#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530526 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800527 "%s:%d: "fmt, __func__, __LINE__, ## args)
528
Govind Singhb6a89772016-08-12 11:23:35 +0530529#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
530 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
531 "%s:%d: "fmt, __func__, __LINE__, ## args)
532
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800533#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
534 do { \
Yun Parkec845302016-12-15 09:22:57 -0800535 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \
536 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800537 } while (0)
538
539#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
540 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
541
542#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
543 do { \
544 hdd_ipa->ipa_rx_internel_drop_count++; \
545 } while (0)
546#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
547 do { \
548 hdd_ipa->ipa_rx_net_send_count++; \
549 } while (0)
550#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
551
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700552#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800553#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
554do { \
555 pipe_in.u.ul.rdy_ring_rp_va = \
556 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
557 pipe_in.u.ul.rdy_comp_ring_base_pa = \
558 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
559 pipe_in.u.ul.rdy_comp_ring_size = \
560 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
561 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
562 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
563 pipe_in.u.ul.rdy_comp_ring_wp_va = \
564 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800565} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700566
567#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800568#else
569/* Do nothing */
570#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
Leo Chang63d73612016-10-18 18:09:43 -0700571#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700572#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800573
Yun Parkb187d542016-11-14 18:10:04 -0800574#define HDD_IPA_DBG_DUMP_RX_LEN 32
575#define HDD_IPA_DBG_DUMP_TX_LEN 48
576
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800577static struct hdd_ipa_adapter_2_client {
578 enum ipa_client_type cons_client;
579 enum ipa_client_type prod_client;
580} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
581 {
582 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
583 }, {
584 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
585 }, {
586 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
587 },
588};
589
590/* For Tx pipes, use Ethernet-II Header format */
591struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
592 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800593 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800594 0x00000000,
595 0x00000000
596 },
597 {
598 0x00000000
599 },
600 {
601 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
602 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
603 0x0008
604 }
605};
606
607/* For Tx pipes, use 802.3 Header format */
608static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
609 {
610 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
611 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
612 0x00 /* length can be zero */
613 },
614 {
615 /* LLC SNAP header 8 bytes */
616 0xaa, 0xaa,
617 {0x03, 0x00, 0x00, 0x00},
618 0x0008 /* type value(2 bytes) ,filled by wlan */
619 /* 0x0800 - IPV4, 0x86dd - IPV6 */
620 }
621};
622
Yun Park637d6482016-10-05 10:51:33 -0700623#ifdef FEATURE_METERING
624#define IPA_UC_SHARING_STATES_WAIT_TIME 500
625#define IPA_UC_SET_QUOTA_WAIT_TIME 500
626#endif
627
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800628static struct hdd_ipa_priv *ghdd_ipa;
629
630/* Local Function Prototypes */
631static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
632 unsigned long data);
633static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
634 unsigned long data);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800635static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800636
637static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700638static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800639
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800640#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
641 defined(IPA_CLIENT_IS_MHI_CONS))
642/**
643 * hdd_ipa_uc_get_db_paddr() - Get Doorbell physical address
644 * @db_paddr: Doorbell physical address should be given bu IPA
645 * @client: IPA client type
646 *
647 * Query doorbell physical address from IPA
648 * IPA will give physical address for TX COMP and RX READY
649 *
650 * Return: None
651 */
652static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
653 enum ipa_client_type client)
654{
655 struct ipa_wdi_db_params dbpa;
656
657 dbpa.client = client;
658 ipa_uc_wdi_get_dbpa(&dbpa);
659 *db_paddr = dbpa.uc_door_bell_pa;
Srinivas Girigowda97852372017-03-06 16:52:59 -0800660 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s PROD DB get dbpa 0x%x",
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800661 __func__, (unsigned int)dbpa.uc_door_bell_pa);
662}
663
664/**
665 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
666 * @priv_ctxt: hdd ipa local context
667 *
668 * Will be called by IPA context.
669 * It's atomic context, then should be scheduled to kworker thread
670 *
671 * Return: None
672 */
673static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
674{
675 struct hdd_ipa_priv *hdd_ipa;
676 struct op_msg_type *msg;
677 struct uc_op_work_struct *uc_op_work;
678
679 if (priv_ctxt == NULL) {
680 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
681 return;
682 }
683
684 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
685 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
686 if (!msg) {
687 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
688 return;
689 }
690
691 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
692
693 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
694
695 /* When the same uC OPCODE is already pended, just return */
696 if (uc_op_work->msg)
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530697 goto done;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800698
699 uc_op_work->msg = msg;
700 schedule_work(&uc_op_work->work);
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530701
702done:
703 qdf_mem_free(msg);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800704}
705
706/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800707 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
708 * @ctrl: WDI control value
709 *
710 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
711 *
712 * Return: 0 on message send to ipa, -1 on failure
713 */
714static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
715{
716 struct ipa_msg_meta meta;
717 struct ipa_wlan_msg *ipa_msg;
718 int ret = 0;
719
720 /* WDI enable message to IPA */
721 meta.msg_len = sizeof(*ipa_msg);
722 ipa_msg = qdf_mem_malloc(meta.msg_len);
723 if (ipa_msg == NULL) {
724 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
725 "msg allocation failed");
726 return -ENOMEM;
727 }
728
729 if (ctrl == true)
730 meta.msg_type = WLAN_WDI_ENABLE;
731 else
732 meta.msg_type = WLAN_WDI_DISABLE;
733
Srinivas Girigowda97852372017-03-06 16:52:59 -0800734 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800735 "ipa_send_msg(Evt:%d)", meta.msg_type);
736 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
737 if (ret) {
738 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
739 "ipa_send_msg(Evt:%d)-fail=%d",
740 meta.msg_type, ret);
741 qdf_mem_free(ipa_msg);
742 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800743 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800744}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800745
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800746/**
747 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
748 * @hdd_ipa: HDD IPA local context
749 *
750 * Register IPA UC ready callback function to IPA kernel driver
751 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
752 * open WDI pipe after WLAN driver loading finished
753 *
754 * Return: 0 Success
755 * -EPERM Registration fail
756 */
757static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
758{
759 struct ipa_wdi_uc_ready_params uc_ready_param;
760 int ret = 0;
761
762 hdd_ipa->uc_loaded = false;
763 uc_ready_param.priv = (void *)hdd_ipa;
764 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
765 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
766 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
767 "UC Ready CB register fail");
768 return -EPERM;
769 }
770 if (true == uc_ready_param.is_uC_ready) {
Srinivas Girigowda2b5d47c2017-03-29 00:28:46 -0700771 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800772 hdd_ipa->uc_loaded = true;
773 } else {
774 ret = hdd_ipa_uc_send_wdi_control_msg(false);
775 }
776
777 return ret;
778}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800779#else
780static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
781 enum ipa_client_type client)
782{
783 /* Do nothing */
784}
785
786static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
787{
788 hdd_ipa->uc_loaded = true;
789 return 0;
790}
791
792static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
793{
794 return 0;
795}
796#endif
797
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800798/**
799 * hdd_ipa_is_enabled() - Is IPA enabled?
800 * @hdd_ctx: Global HDD context
801 *
802 * Return: true if IPA is enabled, false otherwise
803 */
804bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
805{
806 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
807}
808
809/**
810 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
811 * @hdd_ctx: Global HDD context
812 *
813 * Return: true if IPA uC offload is enabled, false otherwise
814 */
815bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
816{
817 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
818}
819
820/**
821 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
822 * @hdd_ctx: Global HDD context
823 *
824 * Return: true if STA mode IPA uC offload is enabled, false otherwise
825 */
826static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
827{
828 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
829}
830
831/**
Guolei Bianca144d82016-11-10 11:07:42 +0800832 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
833 * @hdd_ipa: Global HDD IPA context
834 *
835 * Return: None
836 */
Guolei Bianca144d82016-11-10 11:07:42 +0800837static inline void hdd_ipa_uc_sta_reset_sta_connected(
838 struct hdd_ipa_priv *hdd_ipa)
839{
Yun Park637d6482016-10-05 10:51:33 -0700840 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800841 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700842 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800843}
Guolei Bianca144d82016-11-10 11:07:42 +0800844
845/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800846 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
847 * @hdd_ipa: Global HDD IPA context
848 *
849 * Return: true if pre-filter is enabled, otherwise false
850 */
851static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
852{
853 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
854 HDD_IPA_PRE_FILTER_ENABLE_MASK);
855}
856
857/**
858 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
859 * @hdd_ipa: Global HDD IPA context
860 *
861 * Return: true if IPv6 is enabled, otherwise false
862 */
863static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
864{
865 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
866}
867
868/**
869 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
870 * @hdd_ipa: Global HDD IPA context
871 *
872 * Return: true if resource manager is enabled, otherwise false
873 */
874static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
875{
876 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
877}
878
879/**
880 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
881 * @hdd_ipa: Global HDD IPA context
882 *
883 * Return: true if resource manager is enabled, otherwise false
884 */
885static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
886{
887 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
888}
889
890/**
891 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
892 * @hdd_ipa: Global HDD IPA context
893 *
894 * Return: true if clock scaling is enabled, otherwise false
895 */
896static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
897{
898 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
899 HDD_IPA_CLK_SCALING_ENABLE_MASK |
900 HDD_IPA_RM_ENABLE_MASK);
901}
902
903/**
904 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
905 * @ctext: pointer to hdd context.
906 *
907 * If rt debug enabled, periodically called, and fill debug buffer
908 *
909 * Return: none
910 */
911static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
912{
913 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
914 struct hdd_ipa_priv *hdd_ipa;
915 struct uc_rt_debug_info *dump_info = NULL;
916
917 if (wlan_hdd_validate_context(hdd_ctx))
918 return;
919
920 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800921 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800922 "%s: IPA UC is not enabled", __func__);
923 return;
924 }
925
926 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
927
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530928 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 dump_info = &hdd_ipa->rt_bug_buffer[
930 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
931
Deepthi Gowri6acee342016-10-28 15:00:38 +0530932 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
934 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
935 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800936 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800937 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
938 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800939 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
940 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530941 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800942
Anurag Chouhan210db072016-02-22 18:42:15 +0530943 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
945}
946
947/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700948 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949 * @hdd_ctx: pointer to hdd context.
950 *
951 * If rt debug enabled, dump debug buffer contents based on requirement
952 *
953 * Return: none
954 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700955static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800956{
957 struct hdd_ipa_priv *hdd_ipa;
958 unsigned int dump_count;
959 unsigned int dump_index;
960 struct uc_rt_debug_info *dump_info = NULL;
961
962 if (wlan_hdd_validate_context(hdd_ctx))
963 return;
964
965 hdd_ipa = hdd_ctx->hdd_ipa;
966 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -0800967 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800968 "%s: IPA UC is not enabled", __func__);
969 return;
970 }
971
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530972 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530974 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800975 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800976
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530977 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800978 for (dump_count = 0;
979 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
980 dump_count++) {
981 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
982 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
983 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530984 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530985 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800986 dump_info->time, dump_info->ipa_excep_count,
987 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800988 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989 dump_info->rx_destructor_call,
990 dump_info->rx_discard_count);
991 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530992 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530993 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
995}
996
997/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700998 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
999 * __hdd_ipa_uc_rt_debug_host_dump
1000 * @hdd_ctx: pointer to hdd context.
1001 *
1002 * If rt debug enabled, dump debug buffer contents based on requirement
1003 *
1004 * Return: none
1005 */
1006void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
1007{
1008 cds_ssr_protect(__func__);
1009 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1010 cds_ssr_unprotect(__func__);
1011}
1012
1013/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
1015 * @ctext: pointer to hdd context.
1016 *
1017 * periodically called by timer expire
1018 * will try to alloc dummy memory and detect out of memory condition
1019 * if out of memory detected, dump wlan-ipa stats
1020 *
1021 * Return: none
1022 */
1023static void hdd_ipa_uc_rt_debug_handler(void *ctext)
1024{
1025 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001026 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 void *dummy_ptr = NULL;
1028
1029 if (wlan_hdd_validate_context(hdd_ctx))
1030 return;
1031
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001032 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1033
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001035 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001036 return;
1037 }
1038
1039 /* Allocate dummy buffer periodically and free immediately. this will
1040 * proactively detect OOM and if allocation fails dump ipa stats
1041 */
1042 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
1043 GFP_KERNEL | GFP_ATOMIC);
1044 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001045 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1046 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -07001047 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
1048 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001049 } else {
1050 kfree(dummy_ptr);
1051 }
1052
Anurag Chouhan210db072016-02-22 18:42:15 +05301053 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054 HDD_IPA_UC_RT_DEBUG_PERIOD);
1055}
1056
1057/**
Yun Parkb187d542016-11-14 18:10:04 -08001058 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001059 * @skb: packet pinter
1060 *
1061 * when free data packet, will be invoked by wlan client and will increase
1062 * free counter
1063 *
1064 * Return: none
1065 */
Jeff Johnsond7720632016-10-05 16:04:32 -07001066static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001067{
1068 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301069 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001070 "%s: invalid hdd context", __func__);
1071 return;
1072 }
1073
1074 ghdd_ipa->ipa_rx_destructor_count++;
1075}
1076
1077/**
Yun Parkb187d542016-11-14 18:10:04 -08001078 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001079 * @hdd_ctx: hdd main context
1080 *
1081 * free all rt debugging resources
1082 *
1083 * Return: none
1084 */
1085static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
1086{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001087 struct hdd_ipa_priv *hdd_ipa;
1088
1089 if (wlan_hdd_validate_context(hdd_ctx))
1090 return;
1091
1092 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301094 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001095
1096 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001097 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098 return;
1099 }
1100
Anurag Chouhan210db072016-02-22 18:42:15 +05301101 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001102 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1103 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1104 }
1105 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1106
1107 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301108 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1109 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001110 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301111 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001112}
1113
1114/**
Yun Parkb187d542016-11-14 18:10:04 -08001115 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001116 * @hdd_ctx: hdd main context
1117 *
1118 * alloc and initialize all rt debugging resources
1119 *
1120 * Return: none
1121 */
1122static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
1123{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001124 struct hdd_ipa_priv *hdd_ipa;
1125
1126 if (wlan_hdd_validate_context(hdd_ctx))
1127 return;
1128
1129 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301131 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001132 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301133 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001134 sizeof(struct uc_rt_debug_info) *
1135 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1136 hdd_ipa->ipa_tx_forward = 0;
1137 hdd_ipa->ipa_rx_discard = 0;
1138 hdd_ipa->ipa_rx_net_send_count = 0;
1139 hdd_ipa->ipa_rx_internel_drop_count = 0;
1140 hdd_ipa->ipa_rx_destructor_count = 0;
1141
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142 /* Reatime debug enable on feature enable */
1143 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001144 hdd_debug("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145 return;
1146 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001147
1148 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1149 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1150 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1151 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1152
Anurag Chouhan210db072016-02-22 18:42:15 +05301153 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001154 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301155 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001156 HDD_IPA_UC_RT_DEBUG_PERIOD);
1157
1158}
1159
1160/**
Yun Parkb187d542016-11-14 18:10:04 -08001161 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1162 * @hdd_ipa: HDD IPA struct
1163 *
1164 * Dump entries in struct hdd_ipa
1165 *
1166 * Return: none
1167 */
1168static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1169{
1170 int i;
1171
1172 /* HDD IPA */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001173 hdd_info("==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001174 "num_iface: %d\n"
1175 "rm_state: %d\n"
1176 "rm_lock: %p\n"
1177 "uc_rm_work: %p\n"
1178 "uc_op_work: %p\n"
1179 "wake_lock: %p\n"
1180 "wake_lock_work: %p\n"
1181 "wake_lock_released: %d\n"
1182 "prod_client: %d\n"
1183 "tx_ref_cnt: %d\n"
1184 "pm_queue_head----\n"
1185 "\thead: %p\n"
1186 "\ttail: %p\n"
1187 "\tqlen: %d\n"
1188 "pm_work: %p\n"
1189 "pm_lock: %p\n"
1190 "suspended: %d\n",
1191 hdd_ipa->num_iface,
1192 hdd_ipa->rm_state,
1193 &hdd_ipa->rm_lock,
1194 &hdd_ipa->uc_rm_work,
1195 &hdd_ipa->uc_op_work,
1196 &hdd_ipa->wake_lock,
1197 &hdd_ipa->wake_lock_work,
1198 hdd_ipa->wake_lock_released,
1199 hdd_ipa->prod_client,
1200 hdd_ipa->tx_ref_cnt.counter,
1201 hdd_ipa->pm_queue_head.head,
1202 hdd_ipa->pm_queue_head.tail,
1203 hdd_ipa->pm_queue_head.qlen,
1204 &hdd_ipa->pm_work,
1205 &hdd_ipa->pm_lock,
1206 hdd_ipa->suspended);
Yun Park52b2b992016-09-22 15:49:51 -07001207 hdd_err("\nq_lock: %p\n"
Yun Parkb187d542016-11-14 18:10:04 -08001208 "pend_desc_head----\n"
1209 "\tnext: %p\n"
1210 "\tprev: %p\n"
1211 "hdd_ctx: %p\n"
1212 "debugfs_dir: %p\n"
1213 "stats: %p\n"
1214 "ipv4_notifier: %p\n"
1215 "curr_prod_bw: %d\n"
1216 "curr_cons_bw: %d\n"
1217 "activated_fw_pipe: %d\n"
1218 "sap_num_connected_sta: %d\n"
1219 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001220 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001221 hdd_ipa->pend_desc_head.next,
1222 hdd_ipa->pend_desc_head.prev,
1223 hdd_ipa->hdd_ctx,
1224 hdd_ipa->debugfs_dir,
1225 &hdd_ipa->stats,
1226 &hdd_ipa->ipv4_notifier,
1227 hdd_ipa->curr_prod_bw,
1228 hdd_ipa->curr_cons_bw,
1229 hdd_ipa->activated_fw_pipe,
1230 hdd_ipa->sap_num_connected_sta,
1231 (unsigned int)hdd_ipa->sta_connected
1232 );
Srinivas Girigowda97852372017-03-06 16:52:59 -08001233 hdd_info("\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001234 "rx_pipe_handle: 0x%x\n"
1235 "resource_loading: %d\n"
1236 "resource_unloading: %d\n"
1237 "pending_cons_req: %d\n"
1238 "pending_event----\n"
1239 "\tanchor.next: %p\n"
1240 "\tanchor.prev: %p\n"
1241 "\tcount: %d\n"
1242 "\tmax_size: %d\n"
1243 "event_lock: %p\n"
1244 "ipa_tx_packets_diff: %d\n"
1245 "ipa_rx_packets_diff: %d\n"
1246 "ipa_p_tx_packets: %d\n"
1247 "ipa_p_rx_packets: %d\n"
1248 "stat_req_reason: %d\n",
1249 hdd_ipa->tx_pipe_handle,
1250 hdd_ipa->rx_pipe_handle,
1251 hdd_ipa->resource_loading,
1252 hdd_ipa->resource_unloading,
1253 hdd_ipa->pending_cons_req,
1254 hdd_ipa->pending_event.anchor.next,
1255 hdd_ipa->pending_event.anchor.prev,
1256 hdd_ipa->pending_event.count,
1257 hdd_ipa->pending_event.max_size,
1258 &hdd_ipa->event_lock,
1259 hdd_ipa->ipa_tx_packets_diff,
1260 hdd_ipa->ipa_rx_packets_diff,
1261 hdd_ipa->ipa_p_tx_packets,
1262 hdd_ipa->ipa_p_rx_packets,
1263 hdd_ipa->stat_req_reason);
1264
Srinivas Girigowda97852372017-03-06 16:52:59 -08001265 hdd_info("assoc_stas_map([id]is_reserved/sta_id): ");
Yun Parkb187d542016-11-14 18:10:04 -08001266 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001267 hdd_info(" [%d]%d/%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001268 hdd_ipa->assoc_stas_map[i].is_reserved,
1269 hdd_ipa->assoc_stas_map[i].sta_id);
1270 }
1271}
1272
1273/**
1274 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1275 * @hdd_ipa: HDD IPA struct
1276 *
1277 * Dump entire struct hdd_ipa_sys_pipe
1278 *
1279 * Return: none
1280 */
1281static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1282{
1283 int i;
1284
1285 /* IPA SYS Pipes */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001286 hdd_info("==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001287
1288 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1289 struct hdd_ipa_sys_pipe *sys_pipe;
1290 struct ipa_sys_connect_params *ipa_sys_params;
1291
1292 sys_pipe = &hdd_ipa->sys_pipe[i];
1293 ipa_sys_params = &sys_pipe->ipa_sys_params;
1294
Srinivas Girigowda97852372017-03-06 16:52:59 -08001295 hdd_info("sys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001296 "\tconn_hdl: 0x%x\n"
1297 "\tconn_hdl_valid: %d\n"
1298 "\tnat_en: %d\n"
1299 "\thdr_len %d\n"
1300 "\thdr_additional_const_len: %d\n"
1301 "\thdr_ofst_pkt_size_valid: %d\n"
1302 "\thdr_ofst_pkt_size: %d\n"
1303 "\thdr_little_endian: %d\n"
1304 "\tmode: %d\n"
1305 "\tclient: %d\n"
1306 "\tdesc_fifo_sz: %d\n"
1307 "\tpriv: %p\n"
1308 "\tnotify: %p\n"
1309 "\tskip_ep_cfg: %d\n"
1310 "\tkeep_ipa_awake: %d\n",
1311 i,
1312 sys_pipe->conn_hdl,
1313 sys_pipe->conn_hdl_valid,
1314 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1315 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1316 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1317 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1318 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1319 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1320 ipa_sys_params->ipa_ep_cfg.mode.mode,
1321 ipa_sys_params->client,
1322 ipa_sys_params->desc_fifo_sz,
1323 ipa_sys_params->priv,
1324 ipa_sys_params->notify,
1325 ipa_sys_params->skip_ep_cfg,
1326 ipa_sys_params->keep_ipa_awake);
1327 }
1328}
1329
1330/**
1331 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1332 * @hdd_ipa: HDD IPA struct
1333 *
1334 * Dump entire struct hdd_ipa_iface_context
1335 *
1336 * Return: none
1337 */
1338static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1339{
1340 int i;
1341
1342 /* IPA Interface Contexts */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001343 hdd_info("==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001344
1345 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1346 struct hdd_ipa_iface_context *iface_context;
1347
1348 iface_context = &hdd_ipa->iface_context[i];
1349
Srinivas Girigowda97852372017-03-06 16:52:59 -08001350 hdd_info("iface_context[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001351 "\thdd_ipa: %p\n"
1352 "\tadapter: %p\n"
1353 "\ttl_context: %p\n"
1354 "\tcons_client: %d\n"
1355 "\tprod_client: %d\n"
1356 "\tiface_id: %d\n"
1357 "\tsta_id: %d\n"
1358 "\tinterface_lock: %p\n"
1359 "\tifa_address: 0x%x\n",
1360 i,
1361 iface_context->hdd_ipa,
1362 iface_context->adapter,
1363 iface_context->tl_context,
1364 iface_context->cons_client,
1365 iface_context->prod_client,
1366 iface_context->iface_id,
1367 iface_context->sta_id,
1368 &iface_context->interface_lock,
1369 iface_context->ifa_address);
1370 }
1371}
1372
1373/**
1374 * hdd_ipa_dump_info() - dump HDD IPA struct
1375 * @pHddCtx: hdd main context
1376 *
1377 * Dump entire struct hdd_ipa
1378 *
1379 * Return: none
1380 */
1381void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1382{
1383 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1384
1385 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1386 hdd_ipa_dump_sys_pipe(hdd_ipa);
1387 hdd_ipa_dump_iface_context(hdd_ipa);
1388}
1389
1390/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001391 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1392 * enabled
1393 *
1394 * This routine is called to set TX flow info if IPA is enabled
1395 *
1396 * Return: None
1397 */
1398void hdd_ipa_set_tx_flow_info(void)
1399{
1400 hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL;
1401 QDF_STATUS status;
1402 hdd_adapter_t *adapter;
1403 hdd_station_ctx_t *pHddStaCtx;
1404 hdd_ap_ctx_t *hdd_ap_ctx;
1405 hdd_hostapd_state_t *hostapd_state;
1406 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1407 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1408 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1409 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1410 const char *p2pMode = "DEV";
1411 hdd_context_t *hdd_ctx;
1412 cds_context_type *cds_ctx;
1413#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1414 uint8_t targetChannel = 0;
1415 uint8_t preAdapterChannel = 0;
1416 uint8_t channel24;
1417 uint8_t channel5;
1418 hdd_adapter_t *preAdapterContext = NULL;
1419 hdd_adapter_t *adapter2_4 = NULL;
1420 hdd_adapter_t *adapter5 = NULL;
1421 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1422#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1423 struct wlan_objmgr_psoc *psoc;
1424
1425 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1426 if (!hdd_ctx) {
1427 cds_err("HDD context is NULL");
1428 return;
1429 }
1430
1431 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1432 if (!cds_ctx) {
1433 cds_err("Invalid CDS Context");
1434 return;
1435 }
1436
1437 psoc = hdd_ctx->hdd_psoc;
1438 status = hdd_get_front_adapter(hdd_ctx, &adapterNode);
1439 while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) {
1440 adapter = adapterNode->pAdapter;
1441 switch (adapter->device_mode) {
1442 case QDF_STA_MODE:
1443 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1444 if (eConnectionState_Associated ==
1445 pHddStaCtx->conn_info.connState) {
1446 staChannel =
1447 pHddStaCtx->conn_info.operationChannel;
1448 qdf_copy_macaddr(&staBssid,
1449 &pHddStaCtx->conn_info.bssId);
1450#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1451 targetChannel = staChannel;
1452#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1453 }
1454 break;
1455 case QDF_P2P_CLIENT_MODE:
1456 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1457 if (eConnectionState_Associated ==
1458 pHddStaCtx->conn_info.connState) {
1459 p2pChannel =
1460 pHddStaCtx->conn_info.operationChannel;
1461 qdf_copy_macaddr(&p2pBssid,
1462 &pHddStaCtx->conn_info.bssId);
1463 p2pMode = "CLI";
1464#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1465 targetChannel = p2pChannel;
1466#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1467 }
1468 break;
1469 case QDF_P2P_GO_MODE:
1470 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1471 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1472 if (hostapd_state->bssState == BSS_START
1473 && hostapd_state->qdf_status ==
1474 QDF_STATUS_SUCCESS) {
1475 p2pChannel = hdd_ap_ctx->operatingChannel;
1476 qdf_copy_macaddr(&p2pBssid,
1477 &adapter->macAddressCurrent);
1478#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1479 targetChannel = p2pChannel;
1480#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1481 }
1482 p2pMode = "GO";
1483 break;
1484 case QDF_SAP_MODE:
1485 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1486 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1487 if (hostapd_state->bssState == BSS_START
1488 && hostapd_state->qdf_status ==
1489 QDF_STATUS_SUCCESS) {
1490 apChannel = hdd_ap_ctx->operatingChannel;
1491 qdf_copy_macaddr(&apBssid,
1492 &adapter->macAddressCurrent);
1493#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1494 targetChannel = apChannel;
1495#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1496 }
1497 break;
1498 case QDF_IBSS_MODE:
1499 default:
1500 break;
1501 }
1502#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1503 if (targetChannel) {
1504 /*
1505 * This is first adapter detected as active
1506 * set as default for none concurrency case
1507 */
1508 if (!preAdapterChannel) {
1509 /* If IPA UC data path is enabled,
1510 * target should reserve extra tx descriptors
1511 * for IPA data path.
1512 * Then host data path should allow less TX
1513 * packet pumping in case IPA
1514 * data path enabled
1515 */
1516 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1517 (QDF_SAP_MODE == adapter->device_mode)) {
1518 adapter->tx_flow_low_watermark =
1519 hdd_ctx->config->TxFlowLowWaterMark +
1520 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1521 } else {
1522 adapter->tx_flow_low_watermark =
1523 hdd_ctx->config->
1524 TxFlowLowWaterMark;
1525 }
1526 adapter->tx_flow_high_watermark_offset =
1527 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1528 cdp_fc_ll_set_tx_pause_q_depth(soc,
1529 adapter->sessionId,
1530 hdd_ctx->config->TxFlowMaxQueueDepth);
1531 cds_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
1532 adapter->device_mode,
1533 targetChannel,
1534 adapter->tx_flow_low_watermark,
1535 adapter->tx_flow_low_watermark +
1536 adapter->tx_flow_high_watermark_offset,
1537 hdd_ctx->config->TxFlowMaxQueueDepth);
1538 preAdapterChannel = targetChannel;
1539 preAdapterContext = adapter;
1540 } else {
1541 /*
1542 * SCC, disable TX flow control for both
1543 * SCC each adapter cannot reserve dedicated
1544 * channel resource, as a result, if any adapter
1545 * blocked OS Q by flow control,
1546 * blocked adapter will lost chance to recover
1547 */
1548 if (preAdapterChannel == targetChannel) {
1549 /* Current adapter */
1550 adapter->tx_flow_low_watermark = 0;
1551 adapter->
1552 tx_flow_high_watermark_offset = 0;
1553 cdp_fc_ll_set_tx_pause_q_depth(soc,
1554 adapter->sessionId,
1555 hdd_ctx->config->
1556 TxHbwFlowMaxQueueDepth);
1557 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1558 hdd_device_mode_to_string(
1559 adapter->device_mode),
1560 adapter->device_mode,
1561 targetChannel,
1562 adapter->tx_flow_low_watermark,
1563 adapter->tx_flow_low_watermark +
1564 adapter->
1565 tx_flow_high_watermark_offset,
1566 hdd_ctx->config->
1567 TxHbwFlowMaxQueueDepth);
1568
1569 if (!preAdapterContext) {
1570 cds_err("SCC: Previous adapter context NULL");
1571 continue;
1572 }
1573
1574 /* Previous adapter */
1575 preAdapterContext->
1576 tx_flow_low_watermark = 0;
1577 preAdapterContext->
1578 tx_flow_high_watermark_offset = 0;
1579 cdp_fc_ll_set_tx_pause_q_depth(soc,
1580 preAdapterContext->sessionId,
1581 hdd_ctx->config->
1582 TxHbwFlowMaxQueueDepth);
1583 cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1584 hdd_device_mode_to_string(
1585 preAdapterContext->device_mode
1586 ),
1587 preAdapterContext->device_mode,
1588 targetChannel,
1589 preAdapterContext->
1590 tx_flow_low_watermark,
1591 preAdapterContext->
1592 tx_flow_low_watermark +
1593 preAdapterContext->
1594 tx_flow_high_watermark_offset,
1595 hdd_ctx->config->
1596 TxHbwFlowMaxQueueDepth);
1597 }
1598 /*
1599 * MCC, each adapter will have dedicated
1600 * resource
1601 */
1602 else {
1603 /* current channel is 2.4 */
1604 if (targetChannel <=
1605 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1606 channel24 = targetChannel;
1607 channel5 = preAdapterChannel;
1608 adapter2_4 = adapter;
1609 adapter5 = preAdapterContext;
1610 } else {
1611 /* Current channel is 5 */
1612 channel24 = preAdapterChannel;
1613 channel5 = targetChannel;
1614 adapter2_4 = preAdapterContext;
1615 adapter5 = adapter;
1616 }
1617
1618 if (!adapter5) {
1619 cds_err("MCC: 5GHz adapter context NULL");
1620 continue;
1621 }
1622 adapter5->tx_flow_low_watermark =
1623 hdd_ctx->config->
1624 TxHbwFlowLowWaterMark;
1625 adapter5->
1626 tx_flow_high_watermark_offset =
1627 hdd_ctx->config->
1628 TxHbwFlowHighWaterMarkOffset;
1629 cdp_fc_ll_set_tx_pause_q_depth(soc,
1630 adapter5->sessionId,
1631 hdd_ctx->config->
1632 TxHbwFlowMaxQueueDepth);
1633 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1634 hdd_device_mode_to_string(
1635 adapter5->device_mode),
1636 adapter5->device_mode,
1637 channel5,
1638 adapter5->tx_flow_low_watermark,
1639 adapter5->
1640 tx_flow_low_watermark +
1641 adapter5->
1642 tx_flow_high_watermark_offset,
1643 hdd_ctx->config->
1644 TxHbwFlowMaxQueueDepth);
1645
1646 if (!adapter2_4) {
1647 cds_err("MCC: 2.4GHz adapter context NULL");
1648 continue;
1649 }
1650 adapter2_4->tx_flow_low_watermark =
1651 hdd_ctx->config->
1652 TxLbwFlowLowWaterMark;
1653 adapter2_4->
1654 tx_flow_high_watermark_offset =
1655 hdd_ctx->config->
1656 TxLbwFlowHighWaterMarkOffset;
1657 cdp_fc_ll_set_tx_pause_q_depth(soc,
1658 adapter2_4->sessionId,
1659 hdd_ctx->config->
1660 TxLbwFlowMaxQueueDepth);
1661 cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
1662 hdd_device_mode_to_string(
1663 adapter2_4->device_mode),
1664 adapter2_4->device_mode,
1665 channel24,
1666 adapter2_4->
1667 tx_flow_low_watermark,
1668 adapter2_4->
1669 tx_flow_low_watermark +
1670 adapter2_4->
1671 tx_flow_high_watermark_offset,
1672 hdd_ctx->config->
1673 TxLbwFlowMaxQueueDepth);
1674
1675 }
1676 }
1677 }
1678 targetChannel = 0;
1679#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1680 status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext);
1681 adapterNode = pNext;
1682 }
1683 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1684}
1685
1686/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001687 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001689 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1690 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691 *
1692 * Return: true if IPA is enabled, false otherwise
1693 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001694static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1696{
1697 struct hdd_ipa_priv *hdd_ipa;
1698
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001699 *ipa_tx_diff = 0;
1700 *ipa_rx_diff = 0;
1701
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001702 if (wlan_hdd_validate_context(hdd_ctx))
1703 return;
1704
1705 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1706
1707 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1708 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709 return;
1710 }
1711
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301712 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001713 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1714 (false == hdd_ipa->resource_loading)) {
1715 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1716 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001717 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718 *ipa_tx_diff, *ipa_rx_diff);
1719 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301720 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721}
1722
1723/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001724 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1725 * @hdd_ctx: Global HDD context
1726 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1727 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1728 *
1729 * Return: true if IPA is enabled, false otherwise
1730 */
1731void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1732 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1733{
1734 cds_ssr_protect(__func__);
1735 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1736 cds_ssr_unprotect(__func__);
1737}
1738
1739/**
1740 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001741 * @adapter: network adapter
1742 * @reason: STAT REQ Reason
1743 *
1744 * Return: None
1745 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001746static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001747{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001748 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749 struct hdd_ipa_priv *hdd_ipa;
1750
Yun Park637d6482016-10-05 10:51:33 -07001751 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001754 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1755
1756 if (wlan_hdd_validate_context(hdd_ctx))
1757 return;
1758
1759 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1760 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1761 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762 return;
1763 }
1764
Yun Parkb187d542016-11-14 18:10:04 -08001765 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301766 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1768 (false == hdd_ipa->resource_loading)) {
1769 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07001770 qdf_mutex_release(&hdd_ipa->ipa_lock);
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001771 sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter),
1772 adapter->sessionId,
1773 WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001775 } else {
1776 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001777 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001778}
1779
1780/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001781 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1782 * @adapter: network adapter
1783 * @reason: STAT REQ Reason
1784 *
1785 * Return: None
1786 */
1787void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1788{
1789 cds_ssr_protect(__func__);
1790 __hdd_ipa_uc_stat_request(adapter, reason);
1791 cds_ssr_unprotect(__func__);
1792}
1793
Yun Park637d6482016-10-05 10:51:33 -07001794#ifdef FEATURE_METERING
1795/**
1796 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
1797 * @adapter: network adapter
1798 * @reset_stats: reset stat countis after response
1799 *
1800 * Return: None
1801 */
1802void hdd_ipa_uc_sharing_stats_request(hdd_adapter_t *adapter,
1803 uint8_t reset_stats)
1804{
1805 hdd_context_t *pHddCtx;
1806 struct hdd_ipa_priv *hdd_ipa;
1807
1808 if (!adapter)
1809 return;
1810
1811 pHddCtx = adapter->pHddCtx;
1812 hdd_ipa = pHddCtx->hdd_ipa;
1813 if (!hdd_ipa_is_enabled(pHddCtx) ||
1814 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1815 return;
1816 }
1817
1818 HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats);
1819 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001820 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001821 qdf_mutex_release(&hdd_ipa->ipa_lock);
1822 wma_cli_set_command(
1823 (int)adapter->sessionId,
1824 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
1825 reset_stats, VDEV_CMD);
1826 } else {
1827 qdf_mutex_release(&hdd_ipa->ipa_lock);
1828 }
1829}
1830
1831/**
1832 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
1833 * @adapter: network adapter
1834 * @set_quota: when 1, FW starts quota monitoring
1835 * @quota_bytes: quota limit in bytes
1836 *
1837 * Return: None
1838 */
1839void hdd_ipa_uc_set_quota(hdd_adapter_t *adapter, uint8_t set_quota,
1840 uint64_t quota_bytes)
1841{
1842 hdd_context_t *pHddCtx;
1843 struct hdd_ipa_priv *hdd_ipa;
1844
1845 if (!adapter)
1846 return;
1847
1848 pHddCtx = adapter->pHddCtx;
1849 hdd_ipa = pHddCtx->hdd_ipa;
1850 if (!hdd_ipa_is_enabled(pHddCtx) ||
1851 !(hdd_ipa_uc_is_enabled(pHddCtx))) {
1852 return;
1853 }
1854
1855 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
1856 set_quota, quota_bytes);
1857
1858 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001859 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001860 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park327e7812017-02-14 15:18:10 -08001861 wma_cli_set2_command(
Yun Park637d6482016-10-05 10:51:33 -07001862 (int)adapter->sessionId,
1863 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
Yun Park327e7812017-02-14 15:18:10 -08001864 (set_quota ? quota_bytes&0xffffffff : 0),
1865 (set_quota ? quota_bytes>>32 : 0),
1866 VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001867 } else {
1868 qdf_mutex_release(&hdd_ipa->ipa_lock);
1869 }
1870}
1871#endif
1872
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001873/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001874 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1875 * @hdd_ipa: Global HDD IPA context
1876 * @sta_add: Should station be added
1877 * @sta_id: ID of the station being queried
1878 *
1879 * Return: true if the station was found
1880 */
1881static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1882 bool sta_add, uint8_t sta_id)
1883{
1884 bool sta_found = false;
1885 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001886
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1888 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1889 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1890 sta_found = true;
1891 break;
1892 }
1893 }
1894 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301895 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001896 "%s: STA ID %d already exist, cannot add",
1897 __func__, sta_id);
1898 return sta_found;
1899 }
1900 if (sta_add) {
1901 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1902 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1903 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1904 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1905 return sta_found;
1906 }
1907 }
1908 }
1909 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301910 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911 "%s: STA ID %d does not exist, cannot delete",
1912 __func__, sta_id);
1913 return sta_found;
1914 }
1915 if (!sta_add) {
1916 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1917 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1918 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1919 hdd_ipa->assoc_stas_map[idx].is_reserved =
1920 false;
1921 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1922 return sta_found;
1923 }
1924 }
1925 }
1926 return sta_found;
1927}
1928
1929/**
1930 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1931 * @hdd_ipa: Global HDD IPA context
1932 *
1933 * Return: 0 on success, negative errno if error
1934 */
1935static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1936{
1937 int result;
1938 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001939 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001940
1941 /* ACTIVATE TX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001942 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001943 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1944 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1946 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301947 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948 "%s: Enable TX PIPE fail, code %d",
1949 __func__, result);
1950 return result;
1951 }
1952 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1953 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301954 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001955 "%s: Resume TX PIPE fail, code %d",
1956 __func__, result);
1957 return result;
1958 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001959 cdp_ipa_set_active(soc,
1960 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1961 true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962
1963 /* ACTIVATE RX PIPE */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001964 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07001965 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1966 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1968 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301969 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 "%s: Enable RX PIPE fail, code %d",
1971 __func__, result);
1972 return result;
1973 }
1974 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1975 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301976 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001977 "%s: Resume RX PIPE fail, code %d",
1978 __func__, result);
1979 return result;
1980 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001981 cdp_ipa_set_active(soc,
1982 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1983 true, false);
Leo Change3e49442015-10-26 20:07:13 -07001984 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985 return 0;
1986}
1987
1988/**
1989 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1990 * @hdd_ipa: Global HDD IPA context
1991 *
1992 * Return: 0 on success, negative errno if error
1993 */
1994static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1995{
1996 int result;
1997
Leo Change3e49442015-10-26 20:07:13 -07001998 hdd_ipa->ipa_pipes_down = true;
1999
Srinivas Girigowda97852372017-03-06 16:52:59 -08002000 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002001 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
2002 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302003 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004 "%s: Suspend RX PIPE fail, code %d",
2005 __func__, result);
2006 return result;
2007 }
2008 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
2009 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302010 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 "%s: Disable RX PIPE fail, code %d",
2012 __func__, result);
2013 return result;
2014 }
2015
Srinivas Girigowda97852372017-03-06 16:52:59 -08002016 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
2018 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302019 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020 "%s: Suspend TX PIPE fail, code %d",
2021 __func__, result);
2022 return result;
2023 }
2024 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
2025 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302026 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002027 "%s: Disable TX PIPE fail, code %d",
2028 __func__, result);
2029 return result;
2030 }
2031
2032 return 0;
2033}
2034
2035/**
2036 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
2037 * @hdd_ipa: Global HDD IPA context
2038 *
2039 * Return: 0 on success, negative errno if error
2040 */
2041static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
2042{
2043 hdd_ipa->activated_fw_pipe = 0;
2044 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07002045
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046 /* If RM feature enabled
2047 * Request PROD Resource first
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002048 * PROD resource may return sync or async manners
2049 */
Yun Park4cab6ee2015-10-27 11:43:40 -07002050 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
2051 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
2052 /* RM PROD request sync return
2053 * enable pipe immediately
2054 */
2055 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302056 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07002057 "%s: IPA WDI Pipe activation failed",
2058 __func__);
2059 hdd_ipa->resource_loading = false;
2060 return -EBUSY;
2061 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062 }
2063 } else {
2064 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07002065 * Just enabled all the PIPEs
2066 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002067 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302068 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07002069 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002070 __func__);
2071 hdd_ipa->resource_loading = false;
2072 return -EBUSY;
2073 }
2074 hdd_ipa->resource_loading = false;
2075 }
Yun Park4cab6ee2015-10-27 11:43:40 -07002076
Srinivas Girigowda97852372017-03-06 16:52:59 -08002077 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park4cab6ee2015-10-27 11:43:40 -07002078 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002079 return 0;
2080}
2081
2082/**
2083 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
2084 * @hdd_ipa: Global HDD IPA context
2085 *
2086 * Return: None
2087 */
2088static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
2089{
2090 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07002091 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002092
Yun Park7c4f31b2016-11-30 10:09:21 -08002093 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
2094 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2095 QDF_ASSERT(0);
2096 return;
2097 }
2098
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002099 hdd_ipa->resource_unloading = true;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002100 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW RX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002101 cdp_ipa_set_active(soc,
2102 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2103 false, false);
Srinivas Girigowda97852372017-03-06 16:52:59 -08002104 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW TX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002105 cdp_ipa_set_active(soc,
2106 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2107 false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002108}
2109
2110/**
2111 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2112 * @context: User context registered with TL (the IPA Global context is
2113 * registered
2114 * @rxpkt: Packet containing the notification
2115 * @staid: ID of the station associated with the packet
2116 *
2117 * Return: None
2118 */
2119static void
2120hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
2121{
2122 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302123 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002124
2125 /*
2126 * When SSR is going on or driver is unloading, just return.
2127 */
2128 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302129 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002130 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002131
2132 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2133 return;
2134
Srinivas Girigowda97852372017-03-06 16:52:59 -08002135 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002136 __func__, event);
2137
2138 switch (event) {
2139 case IPA_RM_RESOURCE_GRANTED:
2140 /* Differed RM Granted */
2141 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302142 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002143 if ((false == hdd_ipa->resource_unloading) &&
2144 (!hdd_ipa->activated_fw_pipe)) {
2145 hdd_ipa_uc_enable_pipes(hdd_ipa);
2146 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302147 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002148 break;
2149
2150 case IPA_RM_RESOURCE_RELEASED:
2151 /* Differed RM Released */
2152 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002153 break;
2154
2155 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302156 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002157 "%s, invalid event code %d", __func__, event);
2158 break;
2159 }
2160}
2161
2162/**
2163 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2164 * @hdd_ipa: Global HDD IPA context
2165 * @event: IPA resource manager event to be deferred
2166 *
2167 * This function is called when a resource manager event is received
2168 * from firmware in interrupt context. This function will defer the
2169 * handling to the OL RX thread
2170 *
2171 * Return: None
2172 */
2173static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2174{
2175 enum ipa_rm_event event;
2176 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2177 struct uc_rm_work_struct, work);
2178 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2179 struct hdd_ipa_priv, uc_rm_work);
2180
2181 cds_ssr_protect(__func__);
2182 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002183 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002184 "%s, posted event %d", __func__, event);
2185
2186 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2187 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002188}
2189
2190/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002191 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2192 * @ipa_ctxt: hdd ipa local context
2193 *
2194 * Will handle IPA UC image loaded indication comes from IPA kernel
2195 *
2196 * Return: None
2197 */
2198static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt)
2199{
2200 struct ipa_wdi_out_params pipe_out;
2201
2202 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
2203 if (true == ipa_ctxt->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002204 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002205 __func__);
2206 return;
2207 }
2208
2209 ipa_ctxt->uc_loaded = true;
2210 /* Connect pipe */
2211 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2212 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2213 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
2214 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2215 "%s : TX PIPE Handle %d, DBPA 0x%llx",
2216 __func__, ipa_ctxt->tx_pipe_handle,
2217 (unsigned long long) pipe_out.uc_door_bell_pa);
2218
2219 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2220 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
2221 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2222 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2223 "%s : RX PIPE Handle %d, DBPA 0x%llx",
2224 __func__, ipa_ctxt->rx_pipe_handle,
2225 (unsigned long long) pipe_out.uc_door_bell_pa);
2226
2227 /* If already any STA connected, enable IPA/FW PIPEs */
2228 if (ipa_ctxt->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002229 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002230 "Client already connected, enable IPA/FW PIPEs");
2231 hdd_ipa_uc_handle_first_con(ipa_ctxt);
2232 }
2233}
2234
2235/**
Yun Park637d6482016-10-05 10:51:33 -07002236 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2237 * @hdd_ctx: Global HDD context
2238 * @op_msg: operation message received from firmware
2239 *
2240 * Return: QDF_STATUS enumeration
2241 */
2242#ifdef FEATURE_METERING
2243static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
2244 struct op_msg_type *op_msg)
2245{
2246 struct op_msg_type *msg = op_msg;
2247 struct ipa_uc_sharing_stats *uc_sharing_stats;
2248 struct ipa_uc_quota_rsp *uc_quota_rsp;
2249 struct ipa_uc_quota_ind *uc_quota_ind;
2250 struct hdd_ipa_priv *hdd_ipa;
2251 hdd_adapter_t *adapter;
2252
2253 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2254
2255 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2256 /* fill-up ipa_uc_sharing_stats structure from FW */
2257 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2258 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2259
2260 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2261 sizeof(struct ipa_uc_sharing_stats));
2262
2263 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2264
2265 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2266 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2267 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2268 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2269 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2270 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2271 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2272 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2273 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2274 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2275 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2276 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2277 /* received set quota response */
2278 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2279 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2280
2281 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2282 sizeof(struct ipa_uc_quota_rsp));
2283
2284 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2285 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2286 "%s: success=%d, quota_bytes=%llu",
2287 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2288 hdd_ipa->ipa_quota_rsp.success,
2289 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2290 hdd_ipa->ipa_quota_rsp.quota_lo);
2291 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2292 /* hit quota limit */
2293 uc_quota_ind = (struct ipa_uc_quota_ind *)
2294 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2295
2296 hdd_ipa->ipa_quota_ind.quota_bytes =
2297 uc_quota_ind->quota_bytes;
2298
2299 /* send quota exceeded indication to IPA */
2300 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2301 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2302 hdd_ipa->ipa_quota_ind.quota_bytes);
2303
2304 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2305 if (adapter)
2306 ipa_broadcast_wdi_quota_reach_ind(
2307 adapter->dev->ifindex,
2308 uc_quota_ind->quota_bytes);
2309 else
2310 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2311 "Failed quota_reach_ind: NULL adapter");
2312 } else {
2313 return QDF_STATUS_E_INVAL;
2314 }
2315
2316 return QDF_STATUS_SUCCESS;
2317}
2318#else
2319static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
2320 struct op_msg_type *op_msg)
2321{
2322 return QDF_STATUS_E_INVAL;
2323}
2324#endif
2325
2326/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002327 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2328 * @op_msg: operation message received from firmware
2329 * @usr_ctxt: user context registered with TL (we register the HDD Global
2330 * context)
2331 *
2332 * Return: None
2333 */
2334static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2335{
2336 struct op_msg_type *msg = op_msg;
2337 struct ipa_uc_fw_stats *uc_fw_stat;
2338 struct IpaHwStatsWDIInfoData_t ipa_stat;
2339 struct hdd_ipa_priv *hdd_ipa;
2340 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302341 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002342
2343 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302344 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002345 return;
2346 }
2347
2348 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302349 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002350 "%s, INVALID OPCODE %d", __func__, msg->op_code);
2351 return;
2352 }
2353
2354 hdd_ctx = (hdd_context_t *) usr_ctxt;
2355
2356 /*
2357 * When SSR is going on or driver is unloading, just return.
2358 */
2359 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302360 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302361 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002362 return;
2363 }
2364
2365 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2366
Govind Singhb6a89772016-08-12 11:23:35 +05302367 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002368 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002369
2370 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2371 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302372 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373 hdd_ipa->activated_fw_pipe++;
2374 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2375 hdd_ipa->resource_loading = false;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002376 if (hdd_ipa->wdi_enabled == false) {
2377 hdd_ipa->wdi_enabled = true;
2378 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2379 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2380 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002381 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002382 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002383 if (hdd_ipa->pending_cons_req)
2384 ipa_rm_notify_completion(
2385 IPA_RM_RESOURCE_GRANTED,
2386 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002387 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002388 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302389 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002390 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002391 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302392 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002393 hdd_ipa->activated_fw_pipe--;
2394 if (!hdd_ipa->activated_fw_pipe) {
2395 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002396 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2397 ipa_rm_release_resource(
2398 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08002399 /*
2400 * Sync return success from IPA
2401 * Enable/resume all the PIPEs
2402 */
Yun Park5b635012015-12-02 15:05:01 -08002403 hdd_ipa->resource_unloading = false;
2404 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2405 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002406 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302407 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002408 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002409 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002410 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002411 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302412 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002413 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002414 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002415 "CE RING SIZE: %d\n"
2416 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002417 (unsigned long long)res->ce_sr_base_paddr,
2418 res->ce_sr_ring_size,
2419 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302420 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002421 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002422 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002423 "COMP RING SIZE: %d\n"
2424 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002425 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002426 (unsigned long long)res->tx_comp_ring_base_paddr,
2427 res->tx_comp_ring_size,
2428 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08002429 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302430 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002431 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002432 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002433 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08002434 "IND RING DBELL : 0x%llx\n"
2435 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002436 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08002437 "NUM TX FWD OK : %llu\n"
2438 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08002439 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002440 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08002441 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
2442 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002443 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08002444 hdd_ipa->stats.num_tx_fwd_ok,
2445 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302446 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002447 "==== IPA_UC WLAN_HOST CONTROL ====\n"
2448 "SAP NUM STAs: %d\n"
2449 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08002450 "CONCURRENT MODE: %s\n"
2451 "TX PIPE HDL: 0x%x\n"
2452 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002453 "RSC LOADING : %d\n"
2454 "RSC UNLOADING : %d\n"
2455 "PNDNG CNS RQT : %d",
2456 hdd_ipa->sap_num_connected_sta,
2457 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08002458 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002459 hdd_ipa->tx_pipe_handle,
2460 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08002461 hdd_ipa->resource_loading,
2462 hdd_ipa->resource_unloading,
2463 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002464
2465 /* STATs from FW */
2466 uc_fw_stat = (struct ipa_uc_fw_stats *)
2467 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302468 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002469 "==== IPA_UC WLAN_FW TX ====\n"
2470 "COMP RING BASE: 0x%x\n"
2471 "COMP RING SIZE: %d\n"
2472 "COMP RING DBELL : 0x%x\n"
2473 "COMP RING DBELL IND VAL : %d\n"
2474 "COMP RING DBELL CACHED VAL : %d\n"
2475 "COMP RING DBELL CACHED VAL : %d\n"
2476 "PKTS ENQ : %d\n"
2477 "PKTS COMP : %d\n"
2478 "IS SUSPEND : %d\n"
2479 "RSVD : 0x%x",
2480 uc_fw_stat->tx_comp_ring_base,
2481 uc_fw_stat->tx_comp_ring_size,
2482 uc_fw_stat->tx_comp_ring_dbell_addr,
2483 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2484 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2485 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2486 uc_fw_stat->tx_pkts_enqueued,
2487 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002488 uc_fw_stat->tx_is_suspend,
2489 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302490 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002491 "==== IPA_UC WLAN_FW RX ====\n"
2492 "IND RING BASE: 0x%x\n"
2493 "IND RING SIZE: %d\n"
2494 "IND RING DBELL : 0x%x\n"
2495 "IND RING DBELL IND VAL : %d\n"
2496 "IND RING DBELL CACHED VAL : %d\n"
2497 "RDY IND ADDR : 0x%x\n"
2498 "RDY IND CACHE VAL : %d\n"
2499 "RFIL IND : %d\n"
2500 "NUM PKT INDICAT : %d\n"
2501 "BUF REFIL : %d\n"
2502 "NUM DROP NO SPC : %d\n"
2503 "NUM DROP NO BUF : %d\n"
2504 "IS SUSPND : %d\n"
2505 "RSVD : 0x%x\n",
2506 uc_fw_stat->rx_ind_ring_base,
2507 uc_fw_stat->rx_ind_ring_size,
2508 uc_fw_stat->rx_ind_ring_dbell_addr,
2509 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2510 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2511 uc_fw_stat->rx_ind_ring_rdidx_addr,
2512 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2513 uc_fw_stat->rx_refill_idx,
2514 uc_fw_stat->rx_num_pkts_indicated,
2515 uc_fw_stat->rx_buf_refilled,
2516 uc_fw_stat->rx_num_ind_drop_no_space,
2517 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002518 uc_fw_stat->rx_is_suspend,
2519 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002520 /* STATs from IPA */
2521 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302522 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002523 "==== IPA_UC IPA TX ====\n"
2524 "NUM PROCD : %d\n"
2525 "CE DBELL : 0x%x\n"
2526 "NUM DBELL FIRED : %d\n"
2527 "COMP RNG FULL : %d\n"
2528 "COMP RNG EMPT : %d\n"
2529 "COMP RNG USE HGH : %d\n"
2530 "COMP RNG USE LOW : %d\n"
2531 "BAM FIFO FULL : %d\n"
2532 "BAM FIFO EMPT : %d\n"
2533 "BAM FIFO USE HGH : %d\n"
2534 "BAM FIFO USE LOW : %d\n"
2535 "NUM DBELL : %d\n"
2536 "NUM UNEXP DBELL : %d\n"
2537 "NUM BAM INT HDL : 0x%x\n"
2538 "NUM BAM INT NON-RUN : 0x%x\n"
2539 "NUM QMB INT HDL : 0x%x",
2540 ipa_stat.tx_ch_stats.num_pkts_processed,
2541 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2542 ipa_stat.tx_ch_stats.num_db_fired,
2543 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2544 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2545 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2546 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2547 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2548 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2549 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2550 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2551 ipa_stat.tx_ch_stats.num_db,
2552 ipa_stat.tx_ch_stats.num_unexpected_db,
2553 ipa_stat.tx_ch_stats.num_bam_int_handled,
2554 ipa_stat.tx_ch_stats.
2555 num_bam_int_in_non_runnning_state,
2556 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2557
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302558 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002559 "==== IPA_UC IPA RX ====\n"
2560 "MAX OST PKT : %d\n"
2561 "NUM PKT PRCSD : %d\n"
2562 "RNG RP : 0x%x\n"
2563 "COMP RNG FULL : %d\n"
2564 "COMP RNG EMPT : %d\n"
2565 "COMP RNG USE HGH : %d\n"
2566 "COMP RNG USE LOW : %d\n"
2567 "BAM FIFO FULL : %d\n"
2568 "BAM FIFO EMPT : %d\n"
2569 "BAM FIFO USE HGH : %d\n"
2570 "BAM FIFO USE LOW : %d\n"
2571 "NUM DB : %d\n"
2572 "NUM UNEXP DB : %d\n"
2573 "NUM BAM INT HNDL : 0x%x\n",
2574 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2575 ipa_stat.rx_ch_stats.num_pkts_processed,
2576 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2577 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2578 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2579 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2580 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2581 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2582 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2583 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2584 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2585 ipa_stat.rx_ch_stats.num_db,
2586 ipa_stat.rx_ch_stats.num_unexpected_db,
2587 ipa_stat.rx_ch_stats.num_bam_int_handled);
2588 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2589 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2590 /* STATs from FW */
2591 uc_fw_stat = (struct ipa_uc_fw_stats *)
2592 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302593 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002594 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2595 uc_fw_stat->tx_pkts_completed,
2596 hdd_ipa->ipa_p_tx_packets);
2597 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2598 (uc_fw_stat->rx_num_ind_drop_no_space +
2599 uc_fw_stat->rx_num_ind_drop_no_buf +
2600 uc_fw_stat->rx_num_pkts_indicated),
2601 hdd_ipa->ipa_p_rx_packets);
2602
2603 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2604 hdd_ipa->ipa_p_rx_packets =
2605 (uc_fw_stat->rx_num_ind_drop_no_space +
2606 uc_fw_stat->rx_num_ind_drop_no_buf +
2607 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302608 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002609 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2610 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2611 hdd_ipa_uc_loaded_handler(hdd_ipa);
2612 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002613 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2614 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2615 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002616 }
Yun Park8957d802017-01-25 12:27:29 -08002617
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302618 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002619}
2620
2621
2622/**
2623 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2624 * @adapter: device adapter instance
2625 * @offload_type: MCC or SCC
2626 * @enable: TX offload enable or disable
2627 *
2628 * Return: none
2629 */
2630static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002631 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002632{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002633 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002634 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002635 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002636 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002638 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002639 return;
2640
Yun Park8292dcb2016-10-07 16:46:06 -07002641 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002642 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002643
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002644 if (!iface_context) {
2645 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2646 "Interface context is NULL");
2647 return;
2648 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08002649 if (session_id >= CSR_ROAM_SESSION_MAX) {
2650 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2651 "invalid session id: %d", session_id);
2652 return;
2653 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002654 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002655 /* IPA offload status is already set as desired */
2656 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002657 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
2658 "IPA offload status is already set",
2659 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002660 return;
2661 }
2662
Yun Park4540e862016-11-10 16:30:06 -08002663 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2664 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2665 "invalid session id: %d, offload_type=%d, enable=%d",
2666 adapter->sessionId, offload_type, enable);
2667 return;
2668 }
2669
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302670 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002671 sizeof(ipa_offload_enable_disable));
2672 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002673 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002674 ipa_offload_enable_disable.enable = enable;
2675
Srinivas Girigowda97852372017-03-06 16:52:59 -08002676 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park8292dcb2016-10-07 16:46:06 -07002677 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002678 ipa_offload_enable_disable.offload_type,
2679 ipa_offload_enable_disable.vdev_id,
2680 ipa_offload_enable_disable.enable);
2681
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302682 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002683 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2684 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302685 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002686 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2687 __func__,
2688 ipa_offload_enable_disable.offload_type,
2689 ipa_offload_enable_disable.vdev_id,
2690 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002691 } else {
2692 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002693 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002694 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002695 }
2696}
2697
2698/**
2699 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2700 * @work: uC OP work
2701 *
2702 * Return: None
2703 */
2704static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2705{
2706 struct op_msg_type *msg;
2707 struct uc_op_work_struct *uc_op_work = container_of(work,
2708 struct uc_op_work_struct, work);
2709 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2710
2711 cds_ssr_protect(__func__);
2712
2713 msg = uc_op_work->msg;
2714 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002715 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002716 "%s, posted msg %d", __func__, msg->op_code);
2717
2718 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2719
2720 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002721}
2722
2723/**
2724 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2725 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2726 * @op_msg: operation message received from firmware
2727 * @hdd_ctx: Global HDD context
2728 *
2729 * Return: None
2730 */
2731static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2732{
2733 struct hdd_ipa_priv *hdd_ipa;
2734 struct op_msg_type *msg;
2735 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302736 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002737
2738 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302739 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002740 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002741
2742 msg = (struct op_msg_type *)op_msg;
2743 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2744
2745 if (unlikely(!hdd_ipa))
2746 goto end;
2747
2748 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302749 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002750 __func__, msg->op_code);
2751 goto end;
2752 }
2753
2754 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2755 if (uc_op_work->msg)
2756 /* When the same uC OPCODE is already pended, just return */
2757 goto end;
2758
2759 uc_op_work->msg = msg;
2760 schedule_work(&uc_op_work->work);
2761 return;
2762
2763end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302764 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002765}
2766
2767/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002768 * hdd_ipa_init_uc_op_work - init ipa uc op work
2769 * @work: struct work_struct
2770 * @work_handler: work_handler
2771 *
2772 * Return: none
2773 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002774static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002775 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002776{
2777 INIT_WORK(work, work_handler);
2778}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002779
Yun Park637d6482016-10-05 10:51:33 -07002780#ifdef FEATURE_METERING
2781/**
2782 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2783 * IPA calls to get WLAN stats or set quota limit.
2784 * @priv: pointer to private data registered with IPA (we register a
2785 *» pointer to the global IPA context)
2786 * @evt: the IPA event which triggered the callback
2787 * @data: data associated with the event
2788 *
2789 * Return: None
2790 */
2791static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2792 void *data)
2793{
2794 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2795 hdd_adapter_t *adapter = NULL;
2796 struct ipa_get_wdi_sap_stats *wdi_sap_stats;
2797 struct ipa_set_wifi_quota *ipa_set_quota;
2798 int ret = 0;
2799
2800 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2801 return;
2802
2803 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2804
2805 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2806
2807 switch (evt) {
2808 case IPA_GET_WDI_SAP_STATS:
2809 /* fill-up ipa_get_wdi_sap_stats structure after getting
2810 ipa_uc_fw_stats from FW */
2811 wdi_sap_stats = data;
2812
2813 if (!adapter) {
2814 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2815 "IPA uC share stats failed - no adapter");
2816 wdi_sap_stats->stats_valid = 0;
2817 return;
2818 }
2819
2820 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
2821 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
2822 hdd_ipa_uc_sharing_stats_request(adapter,
2823 wdi_sap_stats->reset_stats);
2824 ret = wait_for_completion_timeout(
2825 &hdd_ipa->ipa_uc_sharing_stats_comp,
2826 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2827 if (!ret) {
2828 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2829 "IPA uC share stats request timed out");
2830 wdi_sap_stats->stats_valid = 0;
2831 } else {
2832 wdi_sap_stats->stats_valid = 1;
2833
2834 wdi_sap_stats->ipv4_rx_packets =
2835 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2836 wdi_sap_stats->ipv4_rx_bytes =
2837 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2838 wdi_sap_stats->ipv6_rx_packets =
2839 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2840 wdi_sap_stats->ipv6_rx_bytes =
2841 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
2842 wdi_sap_stats->ipv4_tx_packets =
2843 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
2844 wdi_sap_stats->ipv4_tx_bytes =
2845 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
2846 wdi_sap_stats->ipv6_tx_packets =
2847 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
2848 wdi_sap_stats->ipv6_tx_bytes =
2849 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
2850 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2851 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2852 "IPA_GET_WDI_SAP_STATS",
2853 wdi_sap_stats->stats_valid,
2854 wdi_sap_stats->ipv4_rx_packets,
2855 wdi_sap_stats->ipv4_rx_bytes,
2856 wdi_sap_stats->ipv6_rx_packets,
2857 wdi_sap_stats->ipv6_rx_bytes,
2858 wdi_sap_stats->ipv4_tx_packets,
2859 wdi_sap_stats->ipv4_tx_bytes,
2860 wdi_sap_stats->ipv6_tx_packets,
2861 wdi_sap_stats->ipv6_tx_bytes);
2862 }
2863 break;
2864 case IPA_SET_WIFI_QUOTA:
2865 /* get ipa_set_wifi_quota structure from IPA and pass to FW
2866 through quota_exceeded field in ipa_uc_fw_stats */
2867 ipa_set_quota = data;
2868
2869 if (!adapter) {
2870 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2871 "IPA uC set quota failed - no adapter");
2872 ipa_set_quota->set_valid = 0;
2873 return;
2874 }
2875
2876 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
2877 ipa_set_quota->quota_bytes);
2878
2879 ret = wait_for_completion_timeout(
2880 &hdd_ipa->ipa_uc_set_quota_comp,
2881 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
2882 if (!ret) {
2883 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2884 "IPA uC set quota request timed out");
2885 ipa_set_quota->set_valid = 0;
2886 } else {
2887 ipa_set_quota->quota_bytes =
2888 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
2889 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
2890 ipa_set_quota->set_valid =
2891 hdd_ipa->ipa_quota_rsp.success;
2892 }
2893
2894 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
2895 ipa_set_quota->quota_bytes,
2896 ipa_set_quota->set_valid);
2897 break;
2898 }
2899}
2900
2901/**
2902 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2903 * IPA calls to get WLAN stats or set quota limit.
2904 * @priv: pointer to private data registered with IPA (we register a
2905 *» pointer to the global IPA context)
2906 * @evt: the IPA event which triggered the callback
2907 * @data: data associated with the event
2908 *
2909 * Return: None
2910 */
2911static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2912 void *data)
2913{
2914 cds_ssr_protect(__func__);
2915 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
2916 cds_ssr_unprotect(__func__);
2917}
2918
2919static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt,
2920 struct ipa_wdi_in_params *pipe_in)
2921{
2922 pipe_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb;
2923
2924 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
2925 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
2926}
2927#else
2928static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt,
2929 struct ipa_wdi_in_params *pipe_in)
2930{
2931}
2932#endif
2933
Rajeev Kumar217f2172016-01-06 18:11:55 -08002934/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002935 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2936 * @hdd_ctx: Global HDD context
2937 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002938 * This function is called to update IPA pipe configuration with resources
2939 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
2940 * (cds_enable)
2941 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302942 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002943 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002944QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002945{
2946 struct ipa_wdi_in_params pipe_in;
2947 struct ipa_wdi_out_params pipe_out;
2948 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07002949 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002950 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2951 int ret;
2952 QDF_STATUS stat = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002953
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002954 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2955 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002956
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002957 ENTER();
2958 /* Do only IPA Pipe specific configuration here. All one time
2959 * initialization wrt IPA UC shall in hdd_ipa_init and those need
2960 * to be reinit at SSR shall in be SSR deinit / reinit functions.
2961 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002962 if (!pdev || !soc) {
2963 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkbaa62862017-01-18 13:43:34 -08002964 stat = QDF_STATUS_E_FAILURE;
2965 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002966 }
Yun Parkbaa62862017-01-18 13:43:34 -08002967
2968 cdp_ipa_get_resource(soc, (void *)pdev, &ipa_ctxt->ipa_resource);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002969 if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) ||
2970 (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2971 (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2972 (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2973 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2974 "IPA UC resource alloc fail");
2975 return QDF_STATUS_E_FAILURE;
2976 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002977 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2978 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302979 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2980 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002981
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002982 /* TX PIPE */
2983 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2984 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2985 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2986 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2987 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2988 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2989 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2990 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2991 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2992 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2993 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2994 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2995 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002996 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2997 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002998 pipe_in.sys.keep_ipa_awake = true;
2999 }
3000
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003001 pipe_in.u.dl.comp_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003002 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Yun Park034e9782017-01-23 16:17:11 -08003003 /* IPA requires total byte counts of Tx comp ring */
Leo Chang3bc8fed2015-11-13 10:59:47 -08003004 pipe_in.u.dl.comp_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003005 ipa_ctxt->ipa_resource.tx_comp_ring_size *
Sravan Kumar Kairam4e82af92017-04-24 18:25:23 +05303006 sizeof(target_paddr_t);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003007 pipe_in.u.dl.ce_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003008 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003009 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
3010 pipe_in.u.dl.ce_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003011 ipa_ctxt->ipa_resource.ce_sr_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003012 pipe_in.u.dl.num_tx_buffers =
Yun Parkbaa62862017-01-18 13:43:34 -08003013 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014
Yun Parkbaa62862017-01-18 13:43:34 -08003015 qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in,
3016 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003017 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08003018 IPA_CLIENT_WLAN1_CONS);
3019
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003020 if (true == ipa_ctxt->uc_loaded) {
3021 /* Connect WDI IPA PIPE */
Yun Parkbaa62862017-01-18 13:43:34 -08003022 ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
3023 if (ret) {
3024 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3025 "ipa_connect_wdi_pipe falied for Tx: ret=%d",
3026 ret);
3027 stat = QDF_STATUS_E_FAILURE;
3028 goto fail_return;
3029 }
Yun Park637d6482016-10-05 10:51:33 -07003030
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003031 /* Micro Controller Doorbell register */
Srinivas Girigowda97852372017-03-06 16:52:59 -08003032 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003033 "CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
3034 (unsigned int)pipe_out.uc_door_bell_pa,
3035 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003036 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Yun Parkbaa62862017-01-18 13:43:34 -08003037
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003038 /* WLAN TX PIPE Handle */
3039 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08003040 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003041 "TX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x, %s %d, %s %d, %s 0x%x",
3042 "comp_ring_base_pa",
3043 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
3044 "comp_ring_size",
3045 pipe_in.u.dl.comp_ring_size,
3046 "ce_ring_base_pa",
3047 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
3048 "ce_door_bell_pa",
3049 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
3050 "ce_ring_size",
3051 pipe_in.u.dl.ce_ring_size,
3052 "num_tx_buffers",
3053 pipe_in.u.dl.num_tx_buffers,
3054 "tx_comp_doorbell_paddr",
3055 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003056 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003057
3058 /* RX PIPE */
3059 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3060 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
3061 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
3062 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
3063 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
3064 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
3065 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
3066 sizeof(struct sps_iovec);
3067 pipe_in.sys.notify = hdd_ipa_w2i_cb;
3068 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303069 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkbaa62862017-01-18 13:43:34 -08003070 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003071 pipe_in.sys.keep_ipa_awake = true;
3072 }
3073
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003074 pipe_in.u.ul.rdy_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003075 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003076 pipe_in.u.ul.rdy_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08003077 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08003078 pipe_in.u.ul.rdy_ring_rp_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08003079 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003080 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Yun Parkbaa62862017-01-18 13:43:34 -08003081
Yun Park637d6482016-10-05 10:51:33 -07003082 hdd_ipa_init_metering(ipa_ctxt, &pipe_in);
3083
Yun Parkbaa62862017-01-18 13:43:34 -08003084 qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in,
3085 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003086 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08003087 IPA_CLIENT_WLAN1_PROD);
3088
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003089 if (true == ipa_ctxt->uc_loaded) {
Yun Parkbaa62862017-01-18 13:43:34 -08003090 ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
3091 if (ret) {
3092 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Sravan Kumar Kairam6b92adf2017-05-02 12:41:16 +05303093 "ipa_connect_wdi_pipe failed for Rx: ret=%d",
Yun Parkbaa62862017-01-18 13:43:34 -08003094 ret);
3095 stat = QDF_STATUS_E_FAILURE;
Sravan Kumar Kairam6b92adf2017-05-02 12:41:16 +05303096 ret = ipa_disconnect_wdi_pipe(ipa_ctxt->tx_pipe_handle);
3097 if (ret)
3098 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3099 "disconnect failed for TX: ret=%d",
3100 ret);
Yun Parkbaa62862017-01-18 13:43:34 -08003101 goto fail_return;
Yun Parkbaa62862017-01-18 13:43:34 -08003102 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003103 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
3104 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Srinivas Girigowda97852372017-03-06 16:52:59 -08003105 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkbaa62862017-01-18 13:43:34 -08003106 "PROD DB pipe out 0x%x TX PIPE Handle 0x%x",
3107 (unsigned int)pipe_out.uc_door_bell_pa,
3108 ipa_ctxt->tx_pipe_handle);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003109 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park637d6482016-10-05 10:51:33 -07003110 "RX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x",
3111 "rdy_ring_base_pa",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003112 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
Yun Park637d6482016-10-05 10:51:33 -07003113 "rdy_ring_size",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003114 pipe_in.u.ul.rdy_ring_size,
Yun Park637d6482016-10-05 10:51:33 -07003115 "rdy_ring_rp_pa",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003116 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
Yun Park637d6482016-10-05 10:51:33 -07003117 "rx_ready_doorbell_paddr",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003118 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
3119 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003120
Yun Parkbaa62862017-01-18 13:43:34 -08003121 cdp_ipa_set_doorbell_paddr(soc, (void *)pdev,
3122 ipa_ctxt->tx_comp_doorbell_paddr,
3123 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003124
Yun Parkbaa62862017-01-18 13:43:34 -08003125 cdp_ipa_register_op_cb(soc, (void *)pdev,
3126 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
3127
3128 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
3129 "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x",
3130 pdev->ipa_uc_op_cb,
3131 (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr,
3132 (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003133
Yun Parkbaa62862017-01-18 13:43:34 -08003134fail_return:
3135 EXIT();
3136 return stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003137}
3138
Leo Change3e49442015-10-26 20:07:13 -07003139/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303140 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
3141 * @hdd_ctx: Global HDD context
3142 *
3143 * Return: 0 on success, negativer errno on error
3144 */
3145int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx)
3146{
3147 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
3148 int ret = 0;
3149
3150 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3151 return ret;
3152
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05303153 if (!hdd_ipa->ipa_pipes_down)
3154 hdd_ipa_uc_disable_pipes(hdd_ipa);
3155
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303156 if (true == hdd_ipa->uc_loaded) {
3157 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
3158 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
3159 __func__, hdd_ipa->tx_pipe_handle);
3160 ret = ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
3161 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
3162 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
3163 __func__, hdd_ipa->rx_pipe_handle);
3164 ret = ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
3165 }
3166
3167 return ret;
3168}
3169
3170/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003171 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07003172 * @hdd_ctx: hdd main context
3173 *
3174 * Force shutdown IPA pipe
3175 * Independent of FW pipe status, IPA pipe shutdonw progress
3176 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3177 * independent from FW pipe status
3178 *
3179 * Return: NONE
3180 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003181static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07003182{
3183 struct hdd_ipa_priv *hdd_ipa;
3184
3185 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
3186 return;
3187
3188 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
3189 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303190 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07003191 "IPA pipes are not down yet, force shutdown");
3192 hdd_ipa_uc_disable_pipes(hdd_ipa);
3193 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003194 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Leo Change3e49442015-10-26 20:07:13 -07003195 "IPA pipes are down, do nothing");
3196 }
Leo Change3e49442015-10-26 20:07:13 -07003197}
3198
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003199/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003200 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
3201 * __hdd_ipa_uc_force_pipe_shutdown
3202 * @hdd_ctx: hdd main context
3203 *
3204 * Force shutdown IPA pipe
3205 * Independent of FW pipe status, IPA pipe shutdonw progress
3206 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3207 * independent from FW pipe status
3208 *
3209 * Return: NONE
3210 */
3211void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
3212{
3213 cds_ssr_protect(__func__);
3214 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
3215 cds_ssr_unprotect(__func__);
3216}
3217
3218/**
Govind Singh9c58eba2016-09-02 16:23:06 +05303219 * hdd_ipa_msg_free_fn() - Free an IPA message
3220 * @buff: pointer to the IPA message
3221 * @len: length of the IPA message
3222 * @type: type of IPA message
3223 *
3224 * Return: None
3225 */
3226static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
3227{
Srinivas Girigowda97852372017-03-06 16:52:59 -08003228 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05303229 ghdd_ipa->stats.num_free_msg++;
3230 qdf_mem_free(buff);
3231}
3232
Govind Singh9c58eba2016-09-02 16:23:06 +05303233/**
jge62037862016-12-09 10:44:33 +08003234 * hdd_ipa_uc_send_evt() - send event to ipa
3235 * @hdd_ctx: pointer to hdd context
3236 * @type: event type
3237 * @mac_addr: pointer to mac address
3238 *
3239 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303240 *
3241 * Return: 0 - Success
3242 */
jge62037862016-12-09 10:44:33 +08003243static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
3244 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303245{
jge62037862016-12-09 10:44:33 +08003246 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05303247 struct ipa_msg_meta meta;
3248 struct ipa_wlan_msg *msg;
3249 int ret = 0;
jge62037862016-12-09 10:44:33 +08003250
3251 meta.msg_len = sizeof(struct ipa_wlan_msg);
3252 msg = qdf_mem_malloc(meta.msg_len);
3253 if (msg == NULL) {
3254 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3255 "msg allocation failed");
3256 return -ENOMEM;
3257 }
3258
3259 meta.msg_type = type;
3260 strlcpy(msg->name, adapter->dev->name,
3261 IPA_RESOURCE_NAME_MAX);
3262 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
Srinivas Girigowda97852372017-03-06 16:52:59 -08003263 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
jge62037862016-12-09 10:44:33 +08003264 msg->name, meta.msg_type);
3265 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
3266 if (ret) {
3267 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3268 "%s: Evt: %d fail:%d",
3269 msg->name, meta.msg_type, ret);
3270 qdf_mem_free(msg);
3271 return ret;
3272 }
3273
3274 hdd_ipa->stats.num_send_msg++;
3275
3276 return ret;
3277}
3278
3279/**
3280 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3281 * @hdd_ctx: pointer to hdd adapter
3282 *
3283 * Send disconnect client event to IPA driver during SSR
3284 *
3285 * Return: 0 - Success
3286 */
3287static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
3288{
3289 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3290 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303291 int i;
3292
3293 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
3294 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
3295 continue;
3296 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08003297 (!adapter->aStaInfo[i].isDeauthInProgress) &&
3298 hdd_ipa->sap_num_connected_sta) {
3299 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
3300 adapter->aStaInfo[i].macAddrSTA.bytes);
3301 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303302 }
3303 }
3304
3305 return ret;
3306}
3307
3308/**
jge62037862016-12-09 10:44:33 +08003309 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3310 * @hdd_ctx: pointer to hdd adapter
3311 *
3312 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303313 *
3314 * Return: 0 - Success
3315 */
jge62037862016-12-09 10:44:33 +08003316
3317static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
3318{
3319 int ret = 0;
3320
3321 if (adapter->ipa_context)
3322 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3323 adapter->dev->dev_addr);
3324
3325 return ret;
3326}
3327
jge62037862016-12-09 10:44:33 +08003328/**
3329 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3330 * @hdd_ctx: pointer to hdd adapter
3331 *
3332 * Send disconnect sta event to IPA driver during SSR
3333 *
3334 * Return: 0 - Success
3335 */
3336static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
3337{
3338 hdd_station_ctx_t *pHddStaCtx;
3339 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3340 int ret = 0;
3341
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003342 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003343 hdd_ipa->sta_connected) {
3344 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
3345 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003346 pHddStaCtx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003347 }
3348
3349 return ret;
3350}
jge62037862016-12-09 10:44:33 +08003351
3352/**
3353 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3354 * @hdd_ctx: pointer to hdd context
3355 *
3356 * Send disconnect event to IPA driver during SSR
3357 *
3358 * Return: 0 - Success
3359 */
3360static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303361{
3362 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
3363 QDF_STATUS status;
3364 hdd_adapter_t *adapter;
3365 int ret = 0;
3366
Govind Singh9c58eba2016-09-02 16:23:06 +05303367 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
3368 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
3369 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08003370 if (adapter->device_mode == QDF_SAP_MODE) {
3371 hdd_ipa_uc_disconnect_client(adapter);
3372 hdd_ipa_uc_disconnect_ap(adapter);
3373 } else if (adapter->device_mode == QDF_STA_MODE) {
3374 hdd_ipa_uc_disconnect_sta(adapter);
3375 }
3376
Govind Singh9c58eba2016-09-02 16:23:06 +05303377 status = hdd_get_next_adapter(
3378 hdd_ctx, adapter_node, &next);
3379 adapter_node = next;
3380 }
3381
3382 return ret;
3383}
3384
3385/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003386 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003387 *
3388 * Deinit basic IPA UC host side to be in sync reloaded FW during
3389 * SSR
3390 *
3391 * Return: 0 - Success
3392 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003393static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003394{
3395 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3396 int idx;
3397 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303398 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003399
Arun Khandavallicc544b32017-01-30 19:52:16 +05303400 if (!hdd_ipa)
3401 return 0;
3402
3403 hdd_ctx = hdd_ipa->hdd_ctx;
3404 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003405 return 0;
3406
jge62037862016-12-09 10:44:33 +08003407 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303408 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003409
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410 /* Clean up HDD IPA interfaces */
3411 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3412 (idx < HDD_IPA_MAX_IFACE); idx++) {
3413 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003414 if (iface_context->adapter && iface_context->adapter->magic ==
3415 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003416 hdd_ipa_cleanup_iface(iface_context);
3417 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003418 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003419 /* After SSR, wlan driver reloads FW again. But we need to protect
3420 * IPA submodule during SSR transient state. So deinit basic IPA
3421 * UC host side to be in sync with reloaded FW during SSR
3422 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303424 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003425 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3426 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3427 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3428 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303429 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003430
Guolei Bianca144d82016-11-10 11:07:42 +08003431 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3432 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3433
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003434 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
3435 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
3436 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
3437 hdd_ipa->uc_op_work[idx].msg = NULL;
3438 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003439 return 0;
3440}
3441
3442/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003443 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3444 *
3445 * Deinit basic IPA UC host side to be in sync reloaded FW during
3446 * SSR
3447 *
3448 * Return: 0 - Success
3449 */
3450int hdd_ipa_uc_ssr_deinit(void)
3451{
3452 int ret;
3453
3454 cds_ssr_protect(__func__);
3455 ret = __hdd_ipa_uc_ssr_deinit();
3456 cds_ssr_unprotect(__func__);
3457
3458 return ret;
3459}
3460
3461/**
3462 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003463 *
3464 * Init basic IPA UC host side to be in sync with reloaded FW after
3465 * SSR to resume IPA UC operations
3466 *
3467 * Return: 0 - Success
3468 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303469static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003470{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003471
Arun Khandavallicc544b32017-01-30 19:52:16 +05303472 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3473 int i;
3474 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303475
3476 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3477 return 0;
3478
Arun Khandavallicc544b32017-01-30 19:52:16 +05303479 /* Create the interface context */
3480 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3481 iface_context = &hdd_ipa->iface_context[i];
3482 iface_context->hdd_ipa = hdd_ipa;
3483 iface_context->cons_client =
3484 hdd_ipa_adapter_2_client[i].cons_client;
3485 iface_context->prod_client =
3486 hdd_ipa_adapter_2_client[i].prod_client;
3487 iface_context->iface_id = i;
3488 iface_context->adapter = NULL;
3489 }
3490 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3491 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3492 hdd_ipa->vdev_offload_enabled[i] = false;
3493 }
3494
3495 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3496 hdd_ipa->resource_loading = false;
3497 hdd_ipa->resource_unloading = false;
3498 hdd_ipa->sta_connected = 0;
3499 hdd_ipa->ipa_pipes_down = true;
3500 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303501 }
3502
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003503 return 0;
3504}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003505
3506/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003507 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3508 *
3509 * Init basic IPA UC host side to be in sync with reloaded FW after
3510 * SSR to resume IPA UC operations
3511 *
3512 * Return: 0 - Success
3513 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303514int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003515{
3516 int ret;
3517
3518 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303519 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003520 cds_ssr_unprotect(__func__);
3521
3522 return ret;
3523}
3524
3525/**
3526 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08003527 * @hdd_ctx: Global HDD context
3528 * @skb: skb sent to IPA
3529 * @session_id: send packet instance session id
3530 *
3531 * Send TX packet which generated by system to IPA.
3532 * This routine only will be used for function verification
3533 *
3534 * Return: NULL packet sent to IPA properly
3535 * NULL invalid packet drop
3536 * skb packet not sent to IPA. legacy data path should handle
3537 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003538static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08003539 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07003540{
Leo Chang3bc8fed2015-11-13 10:59:47 -08003541 struct ipa_header *ipa_header;
3542 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003543 struct hdd_ipa_priv *hdd_ipa;
3544
3545 if (wlan_hdd_validate_context(hdd_ctx))
3546 return skb;
3547
3548 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08003549
3550 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3551 return skb;
3552
Leo Chang07b28f62016-05-11 12:29:22 -07003553 if (!hdd_ipa)
3554 return skb;
3555
3556 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
3557 return skb;
3558
Leo Changcc923e22016-06-16 15:29:03 -07003559 if (skb_headroom(skb) <
3560 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07003561 return skb;
3562
Leo Chang3bc8fed2015-11-13 10:59:47 -08003563 ipa_header = (struct ipa_header *) skb_push(skb,
3564 sizeof(struct ipa_header));
3565 if (!ipa_header) {
3566 /* No headroom, legacy */
3567 return skb;
3568 }
3569 memset(ipa_header, 0, sizeof(*ipa_header));
3570 ipa_header->vdev_id = 0;
3571
3572 frag_header = (struct frag_header *) skb_push(skb,
3573 sizeof(struct frag_header));
3574 if (!frag_header) {
3575 /* No headroom, drop */
3576 kfree_skb(skb);
3577 return NULL;
3578 }
3579 memset(frag_header, 0, sizeof(*frag_header));
3580 frag_header->length = skb->len - sizeof(struct frag_header)
3581 - sizeof(struct ipa_header);
3582
3583 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
3584 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07003585}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003586
3587/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003588 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
3589 * @hdd_ctx: Global HDD context
3590 * @skb: skb sent to IPA
3591 * @session_id: send packet instance session id
3592 *
3593 * Send TX packet which generated by system to IPA.
3594 * This routine only will be used for function verification
3595 *
3596 * Return: NULL packet sent to IPA properly
3597 * NULL invalid packet drop
3598 * skb packet not sent to IPA. legacy data path should handle
3599 */
3600struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
3601 struct sk_buff *skb, uint8_t session_id)
3602{
3603 struct sk_buff *ret;
3604
3605 cds_ssr_protect(__func__);
3606 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
3607 cds_ssr_unprotect(__func__);
3608
3609 return ret;
3610}
3611
3612/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3614 * @work: scheduled work
3615 *
3616 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3617 * not want to immediately release the wake lock since the system
3618 * would then potentially try to suspend when there is a healthy data
3619 * rate. Deferred work is scheduled and this function handles the
3620 * work. When this function is called, if the IPA resource is still
3621 * released then we release the wake lock.
3622 *
3623 * Return: None
3624 */
3625static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3626{
3627 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3628 struct hdd_ipa_priv,
3629 wake_lock_work);
3630
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303631 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003632
3633 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3634 goto end;
3635
3636 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303637 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638 WIFI_POWER_EVENT_WAKELOCK_IPA);
3639
3640end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303641 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003642}
3643
3644/**
3645 * hdd_ipa_rm_request() - Request resource from IPA
3646 * @hdd_ipa: Global HDD IPA context
3647 *
3648 * Return: 0 on success, negative errno on error
3649 */
3650static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3651{
3652 int ret = 0;
3653
3654 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3655 return 0;
3656
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303657 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658
3659 switch (hdd_ipa->rm_state) {
3660 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303661 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003662 return 0;
3663 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303664 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003665 return -EINPROGRESS;
3666 case HDD_IPA_RM_RELEASED:
3667 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3668 break;
3669 }
3670
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303671 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003672
3673 ret = ipa_rm_inactivity_timer_request_resource(
3674 IPA_RM_RESOURCE_WLAN_PROD);
3675
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303676 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003677 if (ret == 0) {
3678 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3679 hdd_ipa->stats.num_rm_grant_imm++;
3680 }
3681
3682 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3683 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303684 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003685 WIFI_POWER_EVENT_WAKELOCK_IPA);
3686 hdd_ipa->wake_lock_released = false;
3687 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303688 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003689
3690 return ret;
3691}
3692
3693/**
3694 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3695 * @hdd_ipa: Global HDD IPA context
3696 *
3697 * Return: 0 if resources released, negative errno otherwise
3698 */
3699static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3700{
3701 int ret = 0;
3702
3703 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3704 return 0;
3705
3706 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3707 return -EAGAIN;
3708
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303709 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003710
Nirav Shahcbc6d722016-03-01 16:24:53 +05303711 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303712 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003713 return -EAGAIN;
3714 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303715 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003716
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303717 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003718 switch (hdd_ipa->rm_state) {
3719 case HDD_IPA_RM_GRANTED:
3720 break;
3721 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303722 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003723 return -EINPROGRESS;
3724 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303725 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003726 return 0;
3727 }
3728
3729 /* IPA driver returns immediately so set the state here to avoid any
3730 * race condition.
3731 */
3732 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3733 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303734 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003735
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003736 ret = ipa_rm_inactivity_timer_release_resource(
3737 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003738
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303739 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003740 if (unlikely(ret != 0)) {
3741 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3742 WARN_ON(1);
3743 }
3744
3745 /*
3746 * If wake_lock is released immediately, kernel would try to suspend
3747 * immediately as well, Just avoid ping-pong between suspend-resume
3748 * while there is healthy amount of data transfer going on by
3749 * releasing the wake_lock after some delay.
3750 */
3751 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3752 msecs_to_jiffies
3753 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3754
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303755 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003756
3757 return ret;
3758}
3759
3760/**
3761 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3762 * @user_data: user data registered with IPA
3763 * @event: the IPA resource manager event that occurred
3764 * @data: the data associated with the event
3765 *
3766 * Return: None
3767 */
3768static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3769 unsigned long data)
3770{
3771 struct hdd_ipa_priv *hdd_ipa = user_data;
3772
3773 if (unlikely(!hdd_ipa))
3774 return;
3775
3776 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3777 return;
3778
Srinivas Girigowda97852372017-03-06 16:52:59 -08003779 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003780
3781 switch (event) {
3782 case IPA_RM_RESOURCE_GRANTED:
3783 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3784 /* RM Notification comes with ISR context
3785 * it should be serialized into work queue to avoid
3786 * ISR sleep problem
3787 */
3788 hdd_ipa->uc_rm_work.event = event;
3789 schedule_work(&hdd_ipa->uc_rm_work.work);
3790 break;
3791 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303792 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003793 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303794 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003795 hdd_ipa->stats.num_rm_grant++;
3796 break;
3797
3798 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003799 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003800 hdd_ipa->resource_unloading = false;
3801 break;
3802
3803 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303804 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003805 break;
3806 }
3807}
3808
3809/**
3810 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3811 *
3812 * Callback function registered with IPA that is called when IPA wants
3813 * to release the WLAN consumer resource
3814 *
3815 * Return: 0 if the request is granted, negative errno otherwise
3816 */
3817static int hdd_ipa_rm_cons_release(void)
3818{
3819 return 0;
3820}
3821
3822/**
3823 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3824 *
3825 * Callback function registered with IPA that is called when IPA wants
3826 * to access the WLAN consumer resource
3827 *
3828 * Return: 0 if the request is granted, negative errno otherwise
3829 */
3830static int hdd_ipa_rm_cons_request(void)
3831{
Yun Park4d8b60a2015-10-22 13:59:32 -07003832 int ret = 0;
3833
3834 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303835 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003836 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003837 __func__);
3838 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003839 ret = -EINPROGRESS;
3840 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303841 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003842 "%s: IPA resource unloading in progress",
3843 __func__);
3844 ghdd_ipa->pending_cons_req = true;
3845 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003846 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003847
3848 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003849}
3850
3851/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003852 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003853 * @hdd_ctx: Global HDD context
3854 * @tx_packets: Number of packets transmitted in the last sample period
3855 * @rx_packets: Number of packets received in the last sample period
3856 *
3857 * Return: 0 on success, negative errno on error
3858 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003859static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003860 uint64_t rx_packets)
3861{
3862 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003863 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003864 struct ipa_rm_perf_profile profile;
3865 int ret;
3866
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003867 if (wlan_hdd_validate_context(hdd_ctx))
3868 return 0;
3869
3870 hdd_ipa = hdd_ctx->hdd_ipa;
3871
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003872 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3873 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3874 return 0;
3875
3876 memset(&profile, 0, sizeof(profile));
3877
3878 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3879 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3880 else if (tx_packets >
3881 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3882 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3883 else
3884 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3885
3886 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3887 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3888 else if (rx_packets >
3889 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3890 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3891 else
3892 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3893
Yun Parkec845302016-12-15 09:22:57 -08003894 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003895 "CONS perf curr: %d, next: %d",
3896 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003897 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003898 "PROD perf curr: %d, next: %d",
3899 hdd_ipa->curr_prod_bw, next_prod_bw);
3900
3901 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003902 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903 hdd_ipa->curr_cons_bw, next_cons_bw);
3904 profile.max_supported_bandwidth_mbps = next_cons_bw;
3905 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3906 &profile);
3907 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003908 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003909
3910 return ret;
3911 }
3912 hdd_ipa->curr_cons_bw = next_cons_bw;
3913 hdd_ipa->stats.num_cons_perf_req++;
3914 }
3915
3916 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003917 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918 hdd_ipa->curr_prod_bw, next_prod_bw);
3919 profile.max_supported_bandwidth_mbps = next_prod_bw;
3920 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3921 &profile);
3922 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003923 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003924 return ret;
3925 }
3926 hdd_ipa->curr_prod_bw = next_prod_bw;
3927 hdd_ipa->stats.num_prod_perf_req++;
3928 }
3929
3930 return 0;
3931}
3932
3933/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003934 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3935 * @hdd_ctx: Global HDD context
3936 * @tx_packets: Number of packets transmitted in the last sample period
3937 * @rx_packets: Number of packets received in the last sample period
3938 *
3939 * Return: 0 on success, negative errno on error
3940 */
3941int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3942 uint64_t rx_packets)
3943{
3944 int ret;
3945
3946 cds_ssr_protect(__func__);
3947 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3948 cds_ssr_unprotect(__func__);
3949
3950 return ret;
3951}
3952
3953/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003954 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3955 * @work: struct work_struct
3956 * @work_handler: work_handler
3957 *
3958 * Return: none
3959 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003960static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3961 work_func_t work_handler)
3962{
3963 INIT_WORK(work, work_handler);
3964}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003965
3966/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967 * hdd_ipa_setup_rm() - Setup IPA resource management
3968 * @hdd_ipa: Global HDD IPA context
3969 *
3970 * Return: 0 on success, negative errno on error
3971 */
3972static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3973{
3974 struct ipa_rm_create_params create_params = { 0 };
3975 int ret;
3976
3977 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3978 return 0;
3979
Rajeev Kumar217f2172016-01-06 18:11:55 -08003980 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3981 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982 memset(&create_params, 0, sizeof(create_params));
3983 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3984 create_params.reg_params.user_data = hdd_ipa;
3985 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3986 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3987
3988 ret = ipa_rm_create_resource(&create_params);
3989 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303990 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003991 "Create RM resource failed: %d", ret);
3992 goto setup_rm_fail;
3993 }
3994
3995 memset(&create_params, 0, sizeof(create_params));
3996 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3997 create_params.request_resource = hdd_ipa_rm_cons_request;
3998 create_params.release_resource = hdd_ipa_rm_cons_release;
3999 create_params.floor_voltage = IPA_VOLTAGE_SVS;
4000
4001 ret = ipa_rm_create_resource(&create_params);
4002 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304003 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004004 "Create RM CONS resource failed: %d", ret);
4005 goto delete_prod;
4006 }
4007
4008 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
4009 IPA_RM_RESOURCE_APPS_CONS);
4010
4011 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
4012 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
4013 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304014 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004015 ret);
4016 goto timer_init_failed;
4017 }
4018
4019 /* Set the lowest bandwidth to start with */
4020 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
4021
4022 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304023 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004024 "Set perf level failed: %d", ret);
4025 goto set_perf_failed;
4026 }
4027
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304028 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004029 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
4030 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304031 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004032 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
4033 hdd_ipa->wake_lock_released = true;
4034 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
4035
4036 return ret;
4037
4038set_perf_failed:
4039 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4040
4041timer_init_failed:
4042 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4043
4044delete_prod:
4045 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4046
4047setup_rm_fail:
4048 return ret;
4049}
4050
4051/**
4052 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
4053 * @hdd_ipa: Global HDD IPA context
4054 *
4055 * Destroys all resources associated with the IPA resource manager
4056 *
4057 * Return: None
4058 */
4059static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
4060{
4061 int ret;
4062
4063 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4064 return;
4065
4066 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304067 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004068
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004069 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304070 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071
4072 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4073
4074 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4075 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304076 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004077 "RM PROD resource delete failed %d", ret);
4078
4079 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4080 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304081 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004082 "RM CONS resource delete failed %d", ret);
4083}
4084
tfyu0380a972017-07-13 18:19:37 +08004085#ifdef QCA_CONFIG_SMP
4086static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4087{
4088 return netif_rx_ni(skb);
4089}
4090#else
4091static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4092{
4093 struct iphdr *ip_h;
4094 static atomic_t softirq_mitigation_cntr =
4095 ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH);
4096 int result;
4097
4098 ip_h = (struct iphdr *)(skb->data);
4099 if ((skb->protocol == htons(ETH_P_IP)) &&
4100 (ip_h->protocol == IPPROTO_ICMP)) {
4101 result = netif_rx_ni(skb);
4102 } else {
4103 /* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets
4104 * to avoid excessive softirq's.
4105 */
4106 if (atomic_dec_and_test(&softirq_mitigation_cntr)) {
4107 result = netif_rx_ni(skb);
4108 atomic_set(&softirq_mitigation_cntr,
4109 IPA_WLAN_RX_SOFTIRQ_THRESH);
4110 } else {
4111 result = netif_rx(skb);
4112 }
4113 }
4114
4115 return result;
4116}
4117#endif
4118
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004119/**
4120 * hdd_ipa_send_skb_to_network() - Send skb to kernel
4121 * @skb: network buffer
4122 * @adapter: network adapter
4123 *
4124 * Called when a network buffer is received which should not be routed
4125 * to the IPA module.
4126 *
4127 * Return: None
4128 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304129static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004130 hdd_adapter_t *adapter)
4131{
tfyu0380a972017-07-13 18:19:37 +08004132 int result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004133 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4134 unsigned int cpu_index;
4135
4136 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004137 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004138 adapter);
4139 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004140 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004141 return;
4142 }
4143
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004144 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004145 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004146 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004147 return;
4148 }
4149
4150 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
4151 skb->dev = adapter->dev;
4152 skb->protocol = eth_type_trans(skb, skb->dev);
4153 skb->ip_summed = CHECKSUM_NONE;
4154
4155 cpu_index = wlan_hdd_get_cpu();
4156
4157 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
tfyu0380a972017-07-13 18:19:37 +08004158 result = hdd_ipa_aggregated_rx_ind(skb);
4159 if (result == NET_RX_SUCCESS)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004160 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
4161 else
4162 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
4163
4164 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
4165 adapter->dev->last_rx = jiffies;
4166}
4167
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004168/**
Leo Chang69c39692016-10-12 20:11:12 -07004169 * hdd_ipa_forward() - handle packet forwarding to wlan tx
4170 * @hdd_ipa: pointer to hdd ipa context
4171 * @adapter: network adapter
4172 * @skb: data pointer
4173 *
4174 * if exception packet has set forward bit, copied new packet should be
4175 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
4176 * put into pm queue and tx procedure will be differed
4177 *
4178 * Return: None
4179 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07004180static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
4181 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07004182{
Leo Chang69c39692016-10-12 20:11:12 -07004183 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
4184
Leo Chang69c39692016-10-12 20:11:12 -07004185 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
4186 /* WLAN subsystem is in suspend, put int queue */
4187 if (hdd_ipa->suspended) {
4188 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4189 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4190 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004191 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
4192 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07004193 pm_tx_cb->exception = true;
4194 pm_tx_cb->adapter = adapter;
4195 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004196 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07004197 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4198 hdd_ipa->stats.num_tx_queued++;
4199 } else {
4200 /* Resume, put packet into WLAN TX */
4201 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004202 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07004203 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4204 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08004205 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07004206 } else {
Yun Parkb187d542016-11-14 18:10:04 -08004207 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07004208 hdd_ipa->ipa_tx_forward++;
4209 }
4210 }
4211}
4212
4213/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004214 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
4215 * @hdd_ipa: pointer to HDD IPA struct
4216 * @adapter: hdd adapter pointer
4217 * @desc: Firmware descriptor
4218 * @skb: Data buffer
4219 *
4220 * Return:
4221 * HDD_IPA_FORWARD_PKT_NONE
4222 * HDD_IPA_FORWARD_PKT_DISCARD
4223 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
4224 *
4225 */
4226
4227static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
4228 struct hdd_ipa_priv *hdd_ipa,
4229 hdd_adapter_t *adapter,
4230 uint8_t desc,
4231 qdf_nbuf_t skb)
4232{
4233 int ret = HDD_IPA_FORWARD_PKT_NONE;
4234
4235 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304236 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004237 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
4238 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304239 /* Drop the packet*/
4240 hdd_ipa->stats.num_tx_fwd_err++;
4241 kfree_skb(skb);
4242 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4243 return ret;
4244 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004245 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
4246 "Forward packet to Tx (fw_desc=%d)", desc);
4247 hdd_ipa->ipa_tx_forward++;
4248
4249 if ((desc & FW_RX_DESC_DISCARD_M)) {
4250 hdd_ipa_forward(hdd_ipa, adapter, skb);
4251 hdd_ipa->ipa_rx_internel_drop_count++;
4252 hdd_ipa->ipa_rx_discard++;
4253 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4254 } else {
4255 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004256
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004257 if (cloned_skb)
4258 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
4259 else
4260 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4261 "%s: tx skb alloc failed",
4262 __func__);
4263 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
4264 }
4265 }
4266
4267 return ret;
4268}
4269
4270/**
Yun Park637d6482016-10-05 10:51:33 -07004271 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004272 * @priv: pointer to private data registered with IPA (we register a
4273 * pointer to the global IPA context)
4274 * @evt: the IPA event which triggered the callback
4275 * @data: data associated with the event
4276 *
4277 * Return: None
4278 */
Yun Parkf8d6a122016-10-11 15:49:43 -07004279static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 unsigned long data)
4281{
4282 struct hdd_ipa_priv *hdd_ipa = NULL;
4283 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304284 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004285 uint8_t iface_id;
4286 uint8_t session_id;
4287 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004288 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07004289 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004290
4291 hdd_ipa = (struct hdd_ipa_priv *)priv;
4292
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08004293 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
4294 return;
4295
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004296 switch (evt) {
4297 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05304298 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07004299
4300 /*
4301 * When SSR is going on or driver is unloading,
4302 * just drop the packets.
4303 */
4304 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4305 if (0 != status) {
4306 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4307 "Invalid context: drop packet");
4308 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4309 kfree_skb(skb);
4310 return;
4311 }
4312
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004313 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4314 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004315 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004316 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004317 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4318 session_id, iface_id);
4319 } else {
4320 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4321 }
4322
4323 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304324 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004325 "IPA_RECEIVE: Invalid iface_id: %u",
4326 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004327 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004328 "w2i -- skb",
4329 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004330 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004331 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004332 return;
4333 }
4334
4335 iface_context = &hdd_ipa->iface_context[iface_id];
4336 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08004337 if (!adapter) {
4338 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4339 "IPA_RECEIVE: Adapter is NULL");
4340 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4341 kfree_skb(skb);
4342 return;
4343 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304345 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004346 "w2i -- skb",
4347 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004348 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4349 hdd_ipa->stats.num_rx_excep++;
4350 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4351 } else {
4352 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4353 }
4354
4355 iface_context->stats.num_rx_ipa_excep++;
4356
4357 /* Disable to forward Intra-BSS Rx packets when
4358 * ap_isolate=1 in hostapd.conf
4359 */
Yun Park046101c2016-09-02 15:32:14 -07004360 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004361 /*
4362 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4363 * all Rx packets to IPA uC, which need to be forwarded
4364 * to other interface.
4365 * And, IPA driver will send back to WLAN host driver
4366 * through exception pipe with fw_desc field set by FW.
4367 * Here we are checking fw_desc field for FORWARD bit
4368 * set, and forward to Tx. Then copy to kernel stack
4369 * only when DISCARD bit is not set.
4370 */
4371 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004372 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4373 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4374 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004375 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004376 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004377 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004378 "Intra-BSS FWD is disabled-skip forward to Tx");
4379 }
4380
4381 hdd_ipa_send_skb_to_network(skb, adapter);
4382 break;
4383
4384 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304385 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386 "w2i cb wrong event: 0x%x", evt);
4387 return;
4388 }
4389}
4390
4391/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004392 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4393 * @priv: pointer to private data registered with IPA (we register a
4394 * pointer to the global IPA context)
4395 * @evt: the IPA event which triggered the callback
4396 * @data: data associated with the event
4397 *
4398 * Return: None
4399 */
4400static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
4401 unsigned long data)
4402{
4403 cds_ssr_protect(__func__);
4404 __hdd_ipa_w2i_cb(priv, evt, data);
4405 cds_ssr_unprotect(__func__);
4406}
4407
4408/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004409 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4410 * @skb: packet buffer which was transmitted
4411 *
4412 * Return: None
4413 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304414void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004415{
4416 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park52b2b992016-09-22 15:49:51 -07004417 struct ipa_rx_data *ipa_tx_desc;
4418 struct hdd_ipa_tx_desc *tx_desc;
4419 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004420
Yun Park52b2b992016-09-22 15:49:51 -07004421 if (!qdf_nbuf_ipa_owned_get(skb)) {
4422 dev_kfree_skb_any(skb);
4423 return;
4424 }
4425
4426 /* Get Tx desc pointer from SKB CB */
4427 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4428 tx_desc = hdd_ipa->tx_desc_list + id;
4429 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4430
4431 /* Return Tx Desc to IPA */
4432 ipa_free_skb(ipa_tx_desc);
4433
4434 /* Return to free tx desc list */
4435 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4436 tx_desc->ipa_tx_desc_ptr = NULL;
4437 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4438 hdd_ipa->stats.num_tx_desc_q_cnt--;
4439 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004440
4441 hdd_ipa->stats.num_tx_comp_cnt++;
4442
4443 atomic_dec(&hdd_ipa->tx_ref_cnt);
4444
4445 hdd_ipa_rm_try_release(hdd_ipa);
4446}
4447
4448/**
4449 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4450 * @iface_context: interface-specific IPA context
4451 * @ipa_tx_desc: packet data descriptor
4452 *
4453 * Return: None
4454 */
4455static void hdd_ipa_send_pkt_to_tl(
4456 struct hdd_ipa_iface_context *iface_context,
4457 struct ipa_rx_data *ipa_tx_desc)
4458{
4459 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004460 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304461 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004462 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004463
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304464 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004465 adapter = iface_context->adapter;
4466 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304467 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468 ipa_free_skb(ipa_tx_desc);
4469 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304470 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471 hdd_ipa_rm_try_release(hdd_ipa);
4472 return;
4473 }
4474
4475 /*
4476 * During CAC period, data packets shouldn't be sent over the air so
4477 * drop all the packets here
4478 */
4479 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4480 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304481 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004482 iface_context->stats.num_tx_cac_drop++;
4483 hdd_ipa_rm_try_release(hdd_ipa);
4484 return;
4485 }
4486
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004487 ++adapter->stats.tx_packets;
4488
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304489 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004490
4491 skb = ipa_tx_desc->skb;
4492
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304493 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004494
4495 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304496 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004497 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304498 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004499 ipa_tx_desc->dma_addr
4500 + HDD_IPA_WLAN_FRAG_HEADER
4501 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502 ipa_tx_desc->skb->len -=
4503 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4504 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304505 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004506
Yun Park52b2b992016-09-22 15:49:51 -07004507 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4508 /* get free Tx desc and assign ipa_tx_desc pointer */
4509 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4510 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4511 struct hdd_ipa_tx_desc, link);
4512 list_del(&tx_desc->link);
4513 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4514 hdd_ipa->stats.num_tx_desc_q_cnt++;
4515 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4516 /* Store Tx Desc index into SKB CB */
4517 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4518 } else {
4519 hdd_ipa->stats.num_tx_desc_error++;
4520 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4521 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "No free Tx desc!");
4522 ipa_free_skb(ipa_tx_desc);
4523 hdd_ipa_rm_try_release(hdd_ipa);
4524 return;
4525 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004526
4527 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
4528
Leo Changfdb45c32016-10-28 11:09:23 -07004529 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004530 (struct cdp_vdev *)iface_context->tl_context,
4531 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004532 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304533 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004534 ipa_free_skb(ipa_tx_desc);
4535 iface_context->stats.num_tx_err++;
4536 hdd_ipa_rm_try_release(hdd_ipa);
4537 return;
4538 }
4539
4540 atomic_inc(&hdd_ipa->tx_ref_cnt);
4541
4542 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004543}
4544
4545/**
Leo Chang11545d62016-10-17 14:53:50 -07004546 * hdd_ipa_is_present() - get IPA hw status
4547 * @hdd_ctx: pointer to hdd context
4548 *
4549 * ipa_uc_reg_rdyCB is not directly designed to check
4550 * ipa hw status. This is an undocumented function which
4551 * has confirmed with IPA team.
4552 *
4553 * Return: true - ipa hw present
4554 * false - ipa hw not present
4555 */
4556bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
4557{
4558 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004559 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004560 return true;
4561 else
4562 return false;
4563}
4564
4565/**
Leo Chang69c39692016-10-12 20:11:12 -07004566 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004567 * @work: pointer to the scheduled work
4568 *
4569 * Called during PM resume to send packets to TL which were queued
4570 * while host was in the process of suspending.
4571 *
4572 * Return: None
4573 */
Leo Chang69c39692016-10-12 20:11:12 -07004574static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004575{
4576 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4577 struct hdd_ipa_priv,
4578 pm_work);
4579 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304580 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004581 uint32_t dequeued = 0;
4582
Leo Chang69c39692016-10-12 20:11:12 -07004583 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4584 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304585 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304586 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4587 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304588 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004589
4590 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004591 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004592 if (pm_tx_cb->exception) {
4593 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4594 "FLUSH EXCEPTION");
4595 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
4596 } else {
4597 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004598 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004599 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304600 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004601 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304602 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004603 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4604 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004605
4606 hdd_ipa->stats.num_tx_dequeued += dequeued;
4607 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4608 hdd_ipa->stats.num_max_pm_queue = dequeued;
4609}
4610
4611/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004612 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 * @priv: pointer to private data registered with IPA (we register a
4614 * pointer to the interface-specific IPA context)
4615 * @evt: the IPA event which triggered the callback
4616 * @data: data associated with the event
4617 *
4618 * Return: None
4619 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004620static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004621 unsigned long data)
4622{
4623 struct hdd_ipa_priv *hdd_ipa = NULL;
4624 struct ipa_rx_data *ipa_tx_desc;
4625 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304626 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004627 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304628 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004629
Mukul Sharma81661ae2015-10-30 20:26:02 +05304630 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004631 ipa_tx_desc = (struct ipa_rx_data *)data;
4632 hdd_ipa = iface_context->hdd_ipa;
4633
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004635 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4636 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637 iface_context->stats.num_tx_drop++;
4638 return;
4639 }
4640
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004641 /*
4642 * When SSR is going on or driver is unloading, just drop the packets.
4643 * During SSR, there is no use in queueing the packets as STA has to
4644 * connect back any way
4645 */
4646 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304647 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004648 ipa_free_skb(ipa_tx_desc);
4649 iface_context->stats.num_tx_drop++;
4650 return;
4651 }
4652
4653 skb = ipa_tx_desc->skb;
4654
Yun Parkb187d542016-11-14 18:10:04 -08004655 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4656 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004657
4658 /*
4659 * If PROD resource is not requested here then there may be cases where
4660 * IPA hardware may be clocked down because of not having proper
4661 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4662 * workaround to request PROD resource while data is going over CONS
4663 * pipe to prevent the IPA hardware clockdown.
4664 */
4665 hdd_ipa_rm_request(hdd_ipa);
4666
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304667 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004668 /*
4669 * If host is still suspended then queue the packets and these will be
4670 * drained later when resume completes. When packet is arrived here and
4671 * host is suspended, this means that there is already resume is in
4672 * progress.
4673 */
4674 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304675 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004676 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4677 pm_tx_cb->iface_context = iface_context;
4678 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304679 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004680 hdd_ipa->stats.num_tx_queued++;
4681
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304682 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004683 return;
4684 }
4685
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304686 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004687
4688 /*
4689 * If we are here means, host is not suspended, wait for the work queue
4690 * to finish.
4691 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004692 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004693
4694 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4695}
4696
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004697/*
4698 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4699 * @priv: pointer to private data registered with IPA (we register a
4700 * pointer to the interface-specific IPA context)
4701 * @evt: the IPA event which triggered the callback
4702 * @data: data associated with the event
4703 *
4704 * Return: None
4705 */
4706static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
4707 unsigned long data)
4708{
4709 cds_ssr_protect(__func__);
4710 __hdd_ipa_i2w_cb(priv, evt, data);
4711 cds_ssr_unprotect(__func__);
4712}
4713
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004714/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004715 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004716 * @hdd_ctx: Global HDD context
4717 *
4718 * Return: 0 on success, negativer errno on error
4719 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004720static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004721{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004722 struct hdd_ipa_priv *hdd_ipa;
4723
4724 if (wlan_hdd_validate_context(hdd_ctx))
4725 return 0;
4726
4727 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004728
4729 if (!hdd_ipa_is_enabled(hdd_ctx))
4730 return 0;
4731
4732 /*
4733 * Check if IPA is ready for suspend, If we are here means, there is
4734 * high chance that suspend would go through but just to avoid any race
4735 * condition after suspend started, these checks are conducted before
4736 * allowing to suspend.
4737 */
4738 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4739 return -EAGAIN;
4740
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304741 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004742
4743 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304744 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004745 return -EAGAIN;
4746 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304747 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004748
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304749 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004750 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304751 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004752
4753 return 0;
4754}
4755
4756/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004757 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4758 * @hdd_ctx: Global HDD context
4759 *
4760 * Return: 0 on success, negativer errno on error
4761 */
4762int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4763{
4764 int ret;
4765
4766 cds_ssr_protect(__func__);
4767 ret = __hdd_ipa_suspend(hdd_ctx);
4768 cds_ssr_unprotect(__func__);
4769
4770 return ret;
4771}
4772
4773/**
4774 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004775 * hdd_ctx: Global HDD context
4776 *
4777 * Return: 0 on success, negative errno on error
4778 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004779static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004780{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004781 struct hdd_ipa_priv *hdd_ipa;
4782
4783 if (wlan_hdd_validate_context(hdd_ctx))
4784 return 0;
4785
4786 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004787
4788 if (!hdd_ipa_is_enabled(hdd_ctx))
4789 return 0;
4790
4791 schedule_work(&hdd_ipa->pm_work);
4792
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304793 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004794 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304795 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004796
4797 return 0;
4798}
4799
4800/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004801 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4802 * hdd_ctx: Global HDD context
4803 *
4804 * Return: 0 on success, negative errno on error
4805 */
4806int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4807{
4808 int ret;
4809
4810 cds_ssr_protect(__func__);
4811 ret = __hdd_ipa_resume(hdd_ctx);
4812 cds_ssr_unprotect(__func__);
4813
4814 return ret;
4815}
4816
4817/**
Yun Park52b2b992016-09-22 15:49:51 -07004818 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
4819 * @hdd_ipa: Global HDD IPA context
4820 *
4821 * Return: 0 on success, negative errno on error
4822 */
4823static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
4824{
4825 int i;
4826 uint32_t max_desc_cnt;
4827 struct hdd_ipa_tx_desc *tmp_desc;
4828
4829 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
4830
4831 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
4832
4833 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc)*max_desc_cnt);
4834
4835 if (!tmp_desc) {
4836 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4837 "Free Tx descriptor allocation failed");
4838 return -ENOMEM;
4839 }
4840
4841 hdd_ipa->tx_desc_list = tmp_desc;
4842
4843 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4844 for (i = 0; i < max_desc_cnt; i++) {
4845 tmp_desc->id = i;
4846 tmp_desc->ipa_tx_desc_ptr = NULL;
4847 list_add_tail(&tmp_desc->link,
4848 &hdd_ipa->free_tx_desc_head);
4849 tmp_desc++;
4850 }
4851
4852 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4853 hdd_ipa->stats.num_tx_desc_error = 0;
4854
4855 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4856
4857 return 0;
4858}
4859
4860/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004861 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4862 * @hdd_ipa: Global HDD IPA context
4863 *
4864 * Return: 0 on success, negative errno on error
4865 */
4866static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4867{
4868 int i, ret = 0;
4869 struct ipa_sys_connect_params *ipa;
4870 uint32_t desc_fifo_sz;
4871
4872 /* The maximum number of descriptors that can be provided to a BAM at
4873 * once is one less than the total number of descriptors that the buffer
4874 * can contain.
4875 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4876 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4877 * be provided at once.
4878 * Because of above requirement, one extra descriptor will be added to
4879 * make sure hardware always has one descriptor.
4880 */
4881 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4882 + sizeof(struct sps_iovec);
4883
4884 /*setup TX pipes */
4885 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4886 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4887
4888 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4889 ipa->desc_fifo_sz = desc_fifo_sz;
4890 ipa->priv = &hdd_ipa->iface_context[i];
4891 ipa->notify = hdd_ipa_i2w_cb;
4892
4893 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4894 ipa->ipa_ep_cfg.hdr.hdr_len =
4895 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4896 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4897 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4898 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4899 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4900 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4901 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4902 } else {
4903 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4904 }
4905 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4906
4907 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4908 ipa->keep_ipa_awake = 1;
4909
4910 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4911 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004912 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4913 "Failed for pipe %d ret: %d", i, ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004914 goto setup_sys_pipe_fail;
4915 }
4916 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4917 }
4918
4919 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4920 /*
4921 * Hard code it here, this can be extended if in case
4922 * PROD pipe is also per interface.
4923 * Right now there is no advantage of doing this.
4924 */
4925 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4926
4927 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4928
4929 ipa->client = hdd_ipa->prod_client;
4930
4931 ipa->desc_fifo_sz = desc_fifo_sz;
4932 ipa->priv = hdd_ipa;
4933 ipa->notify = hdd_ipa_w2i_cb;
4934
4935 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4936 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4937 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4938 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4939
4940 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4941 ipa->keep_ipa_awake = 1;
4942
4943 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4944 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304945 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004946 "Failed for RX pipe: %d", ret);
4947 goto setup_sys_pipe_fail;
4948 }
4949 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4950 }
4951
Yun Park52b2b992016-09-22 15:49:51 -07004952 /* Allocate free Tx desc list */
4953 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
4954 if (ret)
4955 goto setup_sys_pipe_fail;
4956
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004957 return ret;
4958
4959setup_sys_pipe_fail:
4960
4961 while (--i >= 0) {
4962 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304963 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004964 sizeof(struct hdd_ipa_sys_pipe));
4965 }
4966
4967 return ret;
4968}
4969
4970/**
4971 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4972 * @hdd_ipa: Global HDD IPA context
4973 *
4974 * Return: None
4975 */
4976static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4977{
4978 int ret = 0, i;
Yun Park52b2b992016-09-22 15:49:51 -07004979 uint32_t max_desc_cnt;
4980 struct hdd_ipa_tx_desc *tmp_desc;
4981 struct ipa_rx_data *ipa_tx_desc;
4982
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004983 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4984 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4985 ret =
4986 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4987 conn_hdl);
4988 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304989 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004990 ret);
4991
4992 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4993 }
4994 }
Yun Park52b2b992016-09-22 15:49:51 -07004995
4996 if (hdd_ipa->tx_desc_list) {
4997 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
4998
4999 qdf_spin_lock_bh(&hdd_ipa->q_lock);
5000 for (i = 0; i < max_desc_cnt; i++) {
5001 tmp_desc = hdd_ipa->tx_desc_list + i;
5002 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
5003 if (ipa_tx_desc)
5004 ipa_free_skb(ipa_tx_desc);
5005 }
5006 tmp_desc = hdd_ipa->tx_desc_list;
5007 hdd_ipa->tx_desc_list = NULL;
5008 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
5009 hdd_ipa->stats.num_tx_desc_error = 0;
5010 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
5011 qdf_mem_free(tmp_desc);
5012 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005013}
5014
5015/**
5016 * hdd_ipa_register_interface() - register IPA interface
5017 * @hdd_ipa: Global IPA context
5018 * @iface_context: Per-interface IPA context
5019 *
5020 * Return: 0 on success, negative errno on error
5021 */
5022static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
5023 struct hdd_ipa_iface_context
5024 *iface_context)
5025{
5026 struct ipa_tx_intf tx_intf;
5027 struct ipa_rx_intf rx_intf;
5028 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
5029 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
5030 char *ifname = iface_context->adapter->dev->name;
5031
5032 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
5033 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
5034
5035 int num_prop = 1;
5036 int ret = 0;
5037
5038 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
5039 num_prop++;
5040
5041 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
5042 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305043 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005044 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305045 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005046 goto register_interface_fail;
5047 }
5048
5049 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
5050 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305051 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005052 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305053 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005054 goto register_interface_fail;
5055 }
5056
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305057 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
5058 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005059
5060 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
5061 ifname, HDD_IPA_IPV4_NAME_EXT);
5062 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
5063 ifname, HDD_IPA_IPV6_NAME_EXT);
5064
5065 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
5066 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
5067 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5068 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
5069
5070 /*
5071 * Interface ID is 3rd byte in the CLD header. Add the meta data and
5072 * mask to identify the interface in IPA hardware
5073 */
5074 rx_prop[IPA_IP_v4].attrib.meta_data =
5075 htonl(iface_context->adapter->sessionId << 16);
5076 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
5077
5078 rx_intf.num_props++;
5079 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5080 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
5081 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
5082 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5083 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
5084 rx_prop[IPA_IP_v4].attrib.meta_data =
5085 htonl(iface_context->adapter->sessionId << 16);
5086 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
5087
5088 rx_intf.num_props++;
5089 }
5090
5091 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
5092 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5093 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
5094 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
5095 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
5096 IPA_RESOURCE_NAME_MAX);
5097 tx_intf.num_props++;
5098
5099 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5100 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
5101 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
5102 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
5103 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
5104 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
5105 IPA_RESOURCE_NAME_MAX);
5106 tx_intf.num_props++;
5107 }
5108
5109 tx_intf.prop = tx_prop;
5110 rx_intf.prop = rx_prop;
5111
5112 /* Call the ipa api to register interface */
5113 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
5114
Yun Park52b2b992016-09-22 15:49:51 -07005115 /* Register IPA Tx desc free callback */
5116 qdf_nbuf_reg_free_cb(hdd_ipa_nbuf_cb);
5117
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005118register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305119 qdf_mem_free(tx_prop);
5120 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005121 return ret;
5122}
5123
5124/**
5125 * hdd_remove_ipa_header() - Remove a specific header from IPA
5126 * @name: Name of the header to be removed
5127 *
5128 * Return: None
5129 */
5130static void hdd_ipa_remove_header(char *name)
5131{
5132 struct ipa_ioc_get_hdr hdrlookup;
5133 int ret = 0, len;
5134 struct ipa_ioc_del_hdr *ipa_hdr;
5135
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305136 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005137 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
5138 ret = ipa_get_hdr(&hdrlookup);
5139 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005140 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005141 name, ret);
5142 return;
5143 }
5144
Srinivas Girigowda97852372017-03-06 16:52:59 -08005145 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005146 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305147 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005148 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305149 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005150 return;
5151 }
5152 ipa_hdr->num_hdls = 1;
5153 ipa_hdr->commit = 0;
5154 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
5155 ipa_hdr->hdl[0].status = -1;
5156 ret = ipa_del_hdr(ipa_hdr);
5157 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305158 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005159 ret);
5160
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305161 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005162}
5163
5164/**
Yun Parkb187d542016-11-14 18:10:04 -08005165 * wlan_ipa_add_hdr() - Add IPA Tx header
5166 * @ipa_hdr: pointer to IPA header addition parameters
5167 *
5168 * Call IPA API to add IPA Tx header descriptor
5169 * and dump Tx header struct
5170 *
5171 * Return: 0 for success, non-zero for failure
5172 */
5173static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
5174{
5175 int ret;
5176
Srinivas Girigowda97852372017-03-06 16:52:59 -08005177 hdd_debug("==== IPA Tx Header ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08005178 "name: %s\n"
5179 "hdr_len: %d\n"
5180 "type: %d\n"
5181 "is_partial: %d\n"
5182 "hdr_hdl: 0x%x\n"
5183 "status: %d\n"
5184 "is_eth2_ofst_valid: %d\n"
5185 "eth2_ofst: %d\n",
5186 ipa_hdr->hdr[0].name,
5187 ipa_hdr->hdr[0].hdr_len,
5188 ipa_hdr->hdr[0].type,
5189 ipa_hdr->hdr[0].is_partial,
5190 ipa_hdr->hdr[0].hdr_hdl,
5191 ipa_hdr->hdr[0].status,
5192 ipa_hdr->hdr[0].is_eth2_ofst_valid,
5193 ipa_hdr->hdr[0].eth2_ofst);
5194
Srinivas Girigowdac06543c2017-03-09 15:10:03 -08005195 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, "hdr:",
Yun Parkb187d542016-11-14 18:10:04 -08005196 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
5197
5198 ret = ipa_add_hdr(ipa_hdr);
5199 return ret;
5200}
5201
5202/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005203 * hdd_ipa_add_header_info() - Add IPA header for a given interface
5204 * @hdd_ipa: Global HDD IPA context
5205 * @iface_context: Interface-specific HDD IPA context
5206 * @mac_addr: Interface MAC address
5207 *
5208 * Return: 0 on success, negativer errno value on error
5209 */
5210static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
5211 struct hdd_ipa_iface_context *iface_context,
5212 uint8_t *mac_addr)
5213{
5214 hdd_adapter_t *adapter = iface_context->adapter;
5215 char *ifname;
5216 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
5217 int ret = -EINVAL;
5218 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
5219 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
5220
5221 ifname = adapter->dev->name;
5222
Srinivas Girigowda97852372017-03-06 16:52:59 -08005223 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005224 ifname, mac_addr);
5225
5226 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305227 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005228 + sizeof(struct ipa_hdr_add));
5229 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305230 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005231 "%s: ipa_hdr allocation failed", ifname);
5232 ret = -ENOMEM;
5233 goto end;
5234 }
5235
5236 ipa_hdr->commit = 0;
5237 ipa_hdr->num_hdrs = 1;
5238
5239 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5240 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
5241 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
5242 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
5243 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305244 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005245 "ifname=%s, vdev_id=%d",
5246 ifname, uc_tx_hdr->ipa_hd.vdev_id);
5247 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5248 ifname, HDD_IPA_IPV4_NAME_EXT);
5249 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
5250 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
5251 ipa_hdr->hdr[0].is_partial = 1;
5252 ipa_hdr->hdr[0].hdr_hdl = 0;
5253 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
5254 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5255
Yun Parkb187d542016-11-14 18:10:04 -08005256 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005257 } else {
5258 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
5259
5260 /* Set the Source MAC */
5261 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
5262 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
5263
5264 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5265 ifname, HDD_IPA_IPV4_NAME_EXT);
5266 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
5267 ipa_hdr->hdr[0].is_partial = 1;
5268 ipa_hdr->hdr[0].hdr_hdl = 0;
5269 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
5270 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5271
5272 /* Set the type to IPV4 in the header */
5273 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
5274
5275 ret = ipa_add_hdr(ipa_hdr);
5276 }
5277 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305278 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005279 ifname, ret);
5280 goto end;
5281 }
5282
Srinivas Girigowda97852372017-03-06 16:52:59 -08005283 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005284 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
5285
5286 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5287 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5288 ifname, HDD_IPA_IPV6_NAME_EXT);
5289
5290 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5291 uc_tx_hdr =
5292 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
5293 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08005294 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005295 } else {
5296 /* Set the type to IPV6 in the header */
5297 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
5298 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08005299 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005300 }
5301
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005302 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305303 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005304 "%s: IPv6 add hdr failed: %d", ifname, ret);
5305 goto clean_ipv4_hdr;
5306 }
5307
Srinivas Girigowda97852372017-03-06 16:52:59 -08005308 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005309 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
5310 }
5311
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305312 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005313
5314 return ret;
5315
5316clean_ipv4_hdr:
5317 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
5318 ifname, HDD_IPA_IPV4_NAME_EXT);
5319 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
5320end:
5321 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305322 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005323
5324 return ret;
5325}
5326
5327/**
5328 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
5329 * @adapter: Adapter upon which IPA was previously configured
5330 *
5331 * Return: None
5332 */
5333static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
5334{
5335 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5336 int ret;
5337 char name_ipa[IPA_RESOURCE_NAME_MAX];
5338
5339 /* Remove the headers */
5340 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
5341 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
5342 hdd_ipa_remove_header(name_ipa);
5343
5344 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
5345 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
5346 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
5347 hdd_ipa_remove_header(name_ipa);
5348 }
5349 /* unregister the interface with IPA */
5350 ret = ipa_deregister_intf(adapter->dev->name);
5351 if (ret)
Srinivas Girigowda97852372017-03-06 16:52:59 -08005352 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005353 "%s: ipa_deregister_intf fail: %d",
5354 adapter->dev->name, ret);
5355}
5356
5357/**
5358 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
5359 * @iface_context: interface-specific IPA context
5360 *
5361 * Return: None
5362 */
5363static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
5364{
5365 if (iface_context == NULL)
5366 return;
5367
5368 hdd_ipa_clean_hdr(iface_context->adapter);
5369
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305370 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005371 iface_context->adapter->ipa_context = NULL;
5372 iface_context->adapter = NULL;
5373 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305374 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005375 iface_context->ifa_address = 0;
5376 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305377 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005378 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05305379 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005380 }
5381 iface_context->hdd_ipa->num_iface--;
5382}
5383
5384/**
5385 * hdd_ipa_setup_iface() - Setup IPA on a given interface
5386 * @hdd_ipa: HDD IPA global context
5387 * @adapter: Interface upon which IPA is being setup
5388 * @sta_id: Station ID of the API instance
5389 *
5390 * Return: 0 on success, negative errno value on error
5391 */
5392static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
5393 hdd_adapter_t *adapter, uint8_t sta_id)
5394{
5395 struct hdd_ipa_iface_context *iface_context = NULL;
5396 void *tl_context = NULL;
5397 int i, ret = 0;
5398
5399 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
5400 * channel change indication. Since these indications are sent by lower
5401 * layer as SAP updates and IPA doesn't have to do anything for these
5402 * updates so ignoring!
5403 */
Krunal Sonibe766b02016-03-10 13:00:44 -08005404 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005405 return 0;
5406
5407 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5408 if (hdd_ipa->iface_context[i].adapter == NULL) {
5409 iface_context = &(hdd_ipa->iface_context[i]);
5410 break;
5411 }
5412 }
5413
5414 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305415 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005416 "All the IPA interfaces are in use");
5417 ret = -ENOMEM;
5418 goto end;
5419 }
5420
5421 adapter->ipa_context = iface_context;
5422 iface_context->adapter = adapter;
5423 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08005424 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07005425 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005426 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305427 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005428 "Not able to get TL context sta_id: %d", sta_id);
5429 ret = -EINVAL;
5430 goto end;
5431 }
5432
5433 iface_context->tl_context = tl_context;
5434
5435 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
5436 adapter->dev->dev_addr);
5437
5438 if (ret)
5439 goto end;
5440
5441 /* Configure the TX and RX pipes filter rules */
5442 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
5443 if (ret)
5444 goto cleanup_header;
5445
5446 hdd_ipa->num_iface++;
5447 return ret;
5448
5449cleanup_header:
5450
5451 hdd_ipa_clean_hdr(adapter);
5452end:
5453 if (iface_context)
5454 hdd_ipa_cleanup_iface(iface_context);
5455 return ret;
5456}
5457
Yun Parka27049a2016-10-11 12:30:49 -07005458#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005459/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005460 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005461 * @mcc_mode: 0=MCC/1=SCC
5462 *
5463 * Return: 0 on success, negative errno value on error
5464 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005465static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005466{
5467 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305468 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005469 hdd_adapter_t *pAdapter;
5470 struct ipa_msg_meta meta;
5471 struct ipa_wlan_msg *msg;
5472 int ret;
5473
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005474 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005475 return -EINVAL;
5476
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005477 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
5478 return -EINVAL;
5479
5480 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005481 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005482 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305483 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005484 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08005485 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005486 pAdapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005487 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005488 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005489 hdd_deinit_tx_rx(pAdapter);
5490 }
5491 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005492 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005493 adapter_node = next;
5494 }
5495 }
5496
5497 /* Send SCC/MCC Switching event to IPA */
5498 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305499 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005500 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005501 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005502 return -ENOMEM;
5503 }
5504
5505 meta.msg_type = mcc_mode ?
5506 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Srinivas Girigowda97852372017-03-06 16:52:59 -08005507 hdd_debug("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005508
5509 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5510
5511 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005512 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005513 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305514 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005515 }
5516
5517 return ret;
5518}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005519
5520/**
5521 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5522 * @mcc_mode: 0=MCC/1=SCC
5523 *
5524 * Return: 0 on success, negative errno value on error
5525 */
5526int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
5527{
5528 int ret;
5529
5530 cds_ssr_protect(__func__);
5531 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5532 cds_ssr_unprotect(__func__);
5533
5534 return ret;
5535}
Yun Parka27049a2016-10-11 12:30:49 -07005536#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005537
5538/**
5539 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
5540 * @event: IPA WLAN event to be converted to a string
5541 *
5542 * Return: ASCII string representing the IPA WLAN event
5543 */
5544static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
5545{
5546 switch (event) {
5547 case WLAN_CLIENT_CONNECT:
5548 return "WLAN_CLIENT_CONNECT";
5549 case WLAN_CLIENT_DISCONNECT:
5550 return "WLAN_CLIENT_DISCONNECT";
5551 case WLAN_CLIENT_POWER_SAVE_MODE:
5552 return "WLAN_CLIENT_POWER_SAVE_MODE";
5553 case WLAN_CLIENT_NORMAL_MODE:
5554 return "WLAN_CLIENT_NORMAL_MODE";
5555 case SW_ROUTING_ENABLE:
5556 return "SW_ROUTING_ENABLE";
5557 case SW_ROUTING_DISABLE:
5558 return "SW_ROUTING_DISABLE";
5559 case WLAN_AP_CONNECT:
5560 return "WLAN_AP_CONNECT";
5561 case WLAN_AP_DISCONNECT:
5562 return "WLAN_AP_DISCONNECT";
5563 case WLAN_STA_CONNECT:
5564 return "WLAN_STA_CONNECT";
5565 case WLAN_STA_DISCONNECT:
5566 return "WLAN_STA_DISCONNECT";
5567 case WLAN_CLIENT_CONNECT_EX:
5568 return "WLAN_CLIENT_CONNECT_EX";
5569
5570 case IPA_WLAN_EVENT_MAX:
5571 default:
5572 return "UNKNOWN";
5573 }
5574}
5575
5576/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005577 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5578 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5579 *
5580 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
5581 */
5582static enum ipa_wlan_event
5583hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5584{
5585 enum ipa_wlan_event ipa_event;
5586
5587 switch (hdd_ipa_event_type) {
5588 case HDD_IPA_CLIENT_CONNECT:
5589 ipa_event = WLAN_CLIENT_CONNECT;
5590 break;
5591 case HDD_IPA_CLIENT_DISCONNECT:
5592 ipa_event = WLAN_CLIENT_DISCONNECT;
5593 break;
5594 case HDD_IPA_AP_CONNECT:
5595 ipa_event = WLAN_AP_CONNECT;
5596 break;
5597 case HDD_IPA_AP_DISCONNECT:
5598 ipa_event = WLAN_AP_DISCONNECT;
5599 break;
5600 case HDD_IPA_STA_CONNECT:
5601 ipa_event = WLAN_STA_CONNECT;
5602 break;
5603 case HDD_IPA_STA_DISCONNECT:
5604 ipa_event = WLAN_STA_DISCONNECT;
5605 break;
5606 case HDD_IPA_CLIENT_CONNECT_EX:
5607 ipa_event = WLAN_CLIENT_CONNECT_EX;
5608 break;
5609 case HDD_IPA_WLAN_EVENT_MAX:
5610 default:
5611 ipa_event = IPA_WLAN_EVENT_MAX;
5612 break;
5613 }
5614 return ipa_event;
5615
5616}
5617
5618/**
5619 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005620 * @adapter: adapter upon which the event was received
5621 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005622 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005623 * @mac_address: MAC address associated with the event
5624 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005625 * This function is meant to be called from within wlan_hdd_ipa.c
5626 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005627 * Return: 0 on success, negative errno value on error
5628 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07005629static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005630 enum ipa_wlan_event type, uint8_t *mac_addr)
5631{
5632 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5633 struct ipa_msg_meta meta;
5634 struct ipa_wlan_msg *msg;
5635 struct ipa_wlan_msg_ex *msg_ex = NULL;
5636 int ret;
5637
Srinivas Girigowda97852372017-03-06 16:52:59 -08005638 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005639 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5640 mac_addr, sta_id);
5641
5642 if (type >= IPA_WLAN_EVENT_MAX)
5643 return -EINVAL;
5644
5645 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5646 return -EINVAL;
5647
5648 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305649 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005650 return -EINVAL;
5651 }
5652
5653 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5654 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005655 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005656 return 0;
5657 }
5658
5659 /*
5660 * During IPA UC resource loading/unloading new events can be issued.
5661 * Store the events separately and handle them later.
5662 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005663 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5664 if (hdd_ipa->resource_loading) {
5665 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005666 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005667
Yun Park64c405e2017-01-10 22:35:51 -08005668 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5669 "IPA resource load in progress");
Yun Park7c4f31b2016-11-30 10:09:21 -08005670
Yun Park64c405e2017-01-10 22:35:51 -08005671 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005672
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005673 pending_event_count =
5674 qdf_list_size(&hdd_ipa->pending_event);
5675 if (pending_event_count >=
5676 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005677 hdd_debug("Reached max pending event count");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005678 qdf_list_remove_front(&hdd_ipa->pending_event,
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005679 (qdf_list_node_t **)&pending_event);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005680 } else {
5681 pending_event =
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005682 qdf_mem_malloc(sizeof(*pending_event));
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005683 }
5684
5685 if (!pending_event) {
Yun Park64c405e2017-01-10 22:35:51 -08005686 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park7c4f31b2016-11-30 10:09:21 -08005687 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5688 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005689 return -ENOMEM;
5690 }
5691
5692 pending_event->adapter = adapter;
5693 pending_event->sta_id = sta_id;
5694 pending_event->type = type;
5695 qdf_mem_copy(pending_event->mac_addr,
5696 mac_addr,
5697 QDF_MAC_ADDR_SIZE);
5698 qdf_list_insert_back(&hdd_ipa->pending_event,
5699 &pending_event->node);
5700
Yun Park64c405e2017-01-10 22:35:51 -08005701 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005702 return 0;
5703 } else if (hdd_ipa->resource_unloading) {
Yun Park64c405e2017-01-10 22:35:51 -08005704 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5705 "IPA resource unload in progress");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005706 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005707 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005708 }
5709
5710 hdd_ipa->stats.event[type]++;
5711
Leo Chang3bc8fed2015-11-13 10:59:47 -08005712 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005713 switch (type) {
5714 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005715 qdf_mutex_acquire(&hdd_ipa->event_lock);
5716
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005717 /* STA already connected and without disconnect, connect again
5718 * This is Roaming scenario
5719 */
5720 if (hdd_ipa->sta_connected)
5721 hdd_ipa_cleanup_iface(adapter->ipa_context);
5722
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005723 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5724 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305725 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005726 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005727 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005728
Yun Park8f289c82016-10-18 16:38:21 -07005729 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5730 (hdd_ipa->sap_num_connected_sta > 0) &&
5731 !hdd_ipa->sta_connected) {
5732 qdf_mutex_release(&hdd_ipa->event_lock);
5733 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005734 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005735 qdf_mutex_acquire(&hdd_ipa->event_lock);
5736 }
5737
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005738 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005739 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005740 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005741
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005742 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005743
5744 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005745 break;
5746
5747 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005748 qdf_mutex_acquire(&hdd_ipa->event_lock);
5749
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005750 /* For DFS channel we get two start_bss event (before and after
5751 * CAC). Also when ACS range includes both DFS and non DFS
5752 * channels, we could possibly change channel many times due to
5753 * RADAR detection and chosen channel may not be a DFS channels.
5754 * So dont return error here. Just discard the event.
5755 */
Yun Park8f289c82016-10-18 16:38:21 -07005756 if (adapter->ipa_context) {
5757 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005758 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005759 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005760
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005761 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5762 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005763 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005764 hdd_err("%s: Evt: %d, Interface setup failed",
5765 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005766 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005767 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005768
Yun Park8f289c82016-10-18 16:38:21 -07005769 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5770 qdf_mutex_release(&hdd_ipa->event_lock);
5771 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005772 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005773 qdf_mutex_acquire(&hdd_ipa->event_lock);
5774 }
5775
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005776 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005777 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005778 (adapter->ipa_context))->iface_id;
5779
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305780 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005781 break;
5782
5783 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305784 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005785
5786 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005787 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005788 hdd_err("%s: Evt: %d, STA already disconnected",
5789 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005790 return -EINVAL;
5791 }
Yun Parka37592b2016-06-11 17:10:28 -07005792
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005793 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005794
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005795 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005796 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005797 msg_ex->name);
5798 } else {
5799 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005800 if (!hdd_ipa->num_iface &&
5801 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305802 hdd_ipa->activated_fw_pipe) &&
5803 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005804 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005805 }
5806
Yun Park74127cf2016-09-18 11:22:41 -07005807 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5808 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005809 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005810 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005811 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005812 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005813 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5814 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005815 }
5816
Yun Park8f289c82016-10-18 16:38:21 -07005817 hdd_ipa_cleanup_iface(adapter->ipa_context);
5818
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305819 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005820 break;
5821
5822 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005823 qdf_mutex_acquire(&hdd_ipa->event_lock);
5824
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005825 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005826 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005827 hdd_err("%s: Evt: %d, SAP already disconnected",
5828 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005829 return -EINVAL;
5830 }
5831
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005832 if ((!hdd_ipa->num_iface) &&
5833 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305834 hdd_ipa->activated_fw_pipe) &&
5835 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005836 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005837 /*
5838 * We disable WDI pipes directly here since
5839 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5840 * processed when unloading WLAN driver is in
5841 * progress
5842 */
5843 hdd_ipa_uc_disable_pipes(hdd_ipa);
5844 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305845 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005846 "NO INTF left but still pipe clean up");
5847 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5848 }
5849 }
5850
5851 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005852 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005853 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005854 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005855 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005856 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5857 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005858 }
Yun Parka37592b2016-06-11 17:10:28 -07005859
Yun Park8f289c82016-10-18 16:38:21 -07005860 hdd_ipa_cleanup_iface(adapter->ipa_context);
5861
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305862 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005863 break;
5864
5865 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005866 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005867 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005868 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305869 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005870 return 0;
5871 }
5872
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305873 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005874 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5875 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005876 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305877 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005878 "%s: STA ID %d found, not valid",
5879 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005880 return 0;
5881 }
Yun Park312f71a2015-12-08 10:22:42 -08005882
5883 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005884 if (hdd_ipa->sap_num_connected_sta == 0 &&
5885 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005886 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005887 hdd_ipa->sta_connected) {
5888 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005889 hdd_ipa_uc_offload_enable_disable(
5890 hdd_get_adapter(hdd_ipa->hdd_ctx,
5891 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005892 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005893 qdf_mutex_acquire(&hdd_ipa->event_lock);
5894 }
Yun Parka37592b2016-06-11 17:10:28 -07005895
Yun Park312f71a2015-12-08 10:22:42 -08005896 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5897 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305898 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005899 "%s: handle 1st con ret %d",
5900 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005901
5902 if (hdd_ipa_uc_sta_is_enabled(
5903 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005904 hdd_ipa->sta_connected) {
5905 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005906 hdd_ipa_uc_offload_enable_disable(
5907 hdd_get_adapter(
5908 hdd_ipa->hdd_ctx,
5909 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005910 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005911 } else {
5912 qdf_mutex_release(&hdd_ipa->event_lock);
5913 }
Yun Parka37592b2016-06-11 17:10:28 -07005914
Yun Park312f71a2015-12-08 10:22:42 -08005915 return ret;
5916 }
5917 }
5918
5919 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005920
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305921 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005922
5923 meta.msg_type = type;
5924 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5925 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305926 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005927
5928 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305929 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005930 "msg_ex allocation failed");
5931 return -ENOMEM;
5932 }
5933 strlcpy(msg_ex->name, adapter->dev->name,
5934 IPA_RESOURCE_NAME_MAX);
5935 msg_ex->num_of_attribs = 1;
5936 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5937 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5938 msg_ex->attribs[0].offset =
5939 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5940 } else {
5941 msg_ex->attribs[0].offset =
5942 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5943 }
5944 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5945 IPA_MAC_ADDR_SIZE);
5946
5947 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5948
5949 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005950 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305951 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305952 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005953 return ret;
5954 }
5955 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005956 return ret;
5957
5958 case WLAN_CLIENT_DISCONNECT:
5959 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005960 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005961 "%s: IPA UC OFFLOAD NOT ENABLED",
5962 msg_ex->name);
5963 return 0;
5964 }
5965
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305966 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005967 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005968 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305969 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005970 "%s: STA ID %d NOT found, not valid",
5971 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005972 return 0;
5973 }
5974 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005975
Yun Park9b5030f2016-11-08 12:02:37 -08005976 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005977 if (!hdd_ipa->sap_num_connected_sta &&
5978 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005979 if ((false == hdd_ipa->resource_unloading)
5980 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305981 hdd_ipa->activated_fw_pipe) &&
5982 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005983 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5984 }
5985
Yun Park9b5030f2016-11-08 12:02:37 -08005986 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jiad9d472c92017-07-28 14:05:31 +08005987 hdd_ipa->sta_connected) {
5988 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005989 hdd_ipa_uc_offload_enable_disable(
5990 hdd_get_adapter(hdd_ipa->hdd_ctx,
5991 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005992 SIR_STA_RX_DATA_OFFLOAD, false);
jiad9d472c92017-07-28 14:05:31 +08005993 } else {
5994 qdf_mutex_release(&hdd_ipa->event_lock);
5995 }
Yun Park8f289c82016-10-18 16:38:21 -07005996 } else {
5997 qdf_mutex_release(&hdd_ipa->event_lock);
5998 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005999 break;
6000
6001 default:
6002 return 0;
6003 }
6004
6005 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306006 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006007 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306008 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006009 return -ENOMEM;
6010 }
6011
6012 meta.msg_type = type;
6013 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
6014 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
6015
Srinivas Girigowda97852372017-03-06 16:52:59 -08006016 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006017 msg->name, meta.msg_type);
6018
6019 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
6020
6021 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08006022 hdd_err("%s: Evt: %d fail:%d",
6023 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306024 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006025 return ret;
6026 }
6027
6028 hdd_ipa->stats.num_send_msg++;
6029
6030end:
6031 return ret;
6032}
6033
6034/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006035 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07006036 * @adapter: adapter upon which the event was received
6037 * @sta_id: station id for the event
6038 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
6039 * @mac_address: MAC address associated with the event
6040 *
6041 * This function is meant to be called from outside of wlan_hdd_ipa.c.
6042 *
6043 * Return: 0 on success, negative errno value on error
6044 */
6045int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
6046 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
6047{
6048 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006049 int ret = 0;
6050
6051 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07006052
Leo Changa202b522016-10-14 16:13:50 -07006053 /* Data path offload only support for STA and SAP mode */
6054 if ((QDF_STA_MODE == adapter->device_mode) ||
6055 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006056 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07006057
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006058 cds_ssr_unprotect(__func__);
6059
6060 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07006061}
6062
6063/**
6064 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
6065 * @hdd_ipa: Global HDD IPA context
6066 *
6067 * Return: None
6068 */
6069static void
6070hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
6071{
6072 unsigned int pending_event_count;
6073 struct ipa_uc_pending_event *pending_event = NULL;
6074
6075 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08006076 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07006077 "%s, Pending Event Count %d", __func__, pending_event_count);
6078 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08006079 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07006080 "%s, No Pending Event", __func__);
6081 return;
6082 }
6083
6084 qdf_list_remove_front(&hdd_ipa->pending_event,
6085 (qdf_list_node_t **)&pending_event);
6086 while (pending_event != NULL) {
6087 __hdd_ipa_wlan_evt(pending_event->adapter,
6088 pending_event->type,
6089 pending_event->sta_id,
6090 pending_event->mac_addr);
6091 qdf_mem_free(pending_event);
6092 pending_event = NULL;
6093 qdf_list_remove_front(&hdd_ipa->pending_event,
6094 (qdf_list_node_t **)&pending_event);
6095 }
6096}
6097
6098/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006099 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
6100 * @state: IPA RM state value
6101 *
6102 * Return: ASCII string representing the IPA RM state
6103 */
6104static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
6105{
6106 switch (state) {
6107 case HDD_IPA_RM_RELEASED:
6108 return "RELEASED";
6109 case HDD_IPA_RM_GRANT_PENDING:
6110 return "GRANT_PENDING";
6111 case HDD_IPA_RM_GRANTED:
6112 return "GRANTED";
6113 }
6114
6115 return "UNKNOWN";
6116}
6117
6118/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006119 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006120 * @hdd_ctx: HDD global context
6121 *
6122 * Allocate hdd_ipa resources, ipa pipe resource and register
6123 * wlan interface with IPA module.
6124 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306125 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006126 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006127static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006128{
6129 struct hdd_ipa_priv *hdd_ipa = NULL;
6130 int ret, i;
6131 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08006132 struct ol_txrx_pdev_t *pdev = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006133
6134 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306135 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006136
Yun Parkbaa62862017-01-18 13:43:34 -08006137 ENTER();
6138
6139 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07006140 if (!pdev) {
6141 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
6142 goto fail_return;
6143 }
6144
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306145 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006146 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306147 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08006148 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006149 }
6150
6151 hdd_ctx->hdd_ipa = hdd_ipa;
6152 ghdd_ipa = hdd_ipa;
6153 hdd_ipa->hdd_ctx = hdd_ctx;
6154 hdd_ipa->num_iface = 0;
6155
6156 /* Create the interface context */
6157 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6158 iface_context = &hdd_ipa->iface_context[i];
6159 iface_context->hdd_ipa = hdd_ipa;
6160 iface_context->cons_client =
6161 hdd_ipa_adapter_2_client[i].cons_client;
6162 iface_context->prod_client =
6163 hdd_ipa_adapter_2_client[i].prod_client;
6164 iface_context->iface_id = i;
6165 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306166 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08006167 }
6168 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08006169 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
6170 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006171 }
6172
Leo Chang69c39692016-10-12 20:11:12 -07006173 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306174 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006175 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05306176 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08006177 qdf_list_create(&hdd_ipa->pending_event, 1000);
6178 qdf_mutex_create(&hdd_ipa->event_lock);
6179 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006180
6181 ret = hdd_ipa_setup_rm(hdd_ipa);
6182 if (ret)
6183 goto fail_setup_rm;
6184
6185 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
6186 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306187 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006188 hdd_ipa->sap_num_connected_sta = 0;
6189 hdd_ipa->ipa_tx_packets_diff = 0;
6190 hdd_ipa->ipa_rx_packets_diff = 0;
6191 hdd_ipa->ipa_p_tx_packets = 0;
6192 hdd_ipa->ipa_p_rx_packets = 0;
6193 hdd_ipa->resource_loading = false;
6194 hdd_ipa->resource_unloading = false;
6195 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07006196 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08006197 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006198 /* Setup IPA sys_pipe for MCC */
6199 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
6200 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6201 if (ret)
6202 goto fail_create_sys_pipe;
6203 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08006204 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
6205 goto fail_create_sys_pipe;
Manikandan Mohan2e803a02017-02-14 14:57:53 -08006206
6207 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6208 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
6209 hdd_ipa_uc_fw_op_event_handler);
6210 hdd_ipa->uc_op_work[i].msg = NULL;
6211 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006212 } else {
6213 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6214 if (ret)
6215 goto fail_create_sys_pipe;
6216 }
6217
Yun Parkbaa62862017-01-18 13:43:34 -08006218 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306219 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006220
6221fail_create_sys_pipe:
6222 hdd_ipa_destroy_rm_resource(hdd_ipa);
6223fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306224 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306225 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08006226 hdd_ctx->hdd_ipa = NULL;
6227 ghdd_ipa = NULL;
6228fail_return:
Yun Parkbaa62862017-01-18 13:43:34 -08006229 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306230 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006231}
6232
6233/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006234 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
6235 * @hdd_ctx: HDD global context
6236 *
6237 * Allocate hdd_ipa resources, ipa pipe resource and register
6238 * wlan interface with IPA module.
6239 *
6240 * Return: QDF_STATUS enumeration
6241 */
6242QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
6243{
6244 QDF_STATUS ret;
6245
6246 cds_ssr_protect(__func__);
6247 ret = __hdd_ipa_init(hdd_ctx);
6248 cds_ssr_unprotect(__func__);
6249
6250 return ret;
6251}
6252
Arun Khandavallicc544b32017-01-30 19:52:16 +05306253
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006254/**
Yun Parkf19e07d2015-11-20 11:34:27 -08006255 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
6256 * @hdd_ipa: pointer to HDD IPA struct
6257 *
6258 * Return: none
6259 */
Jeff Johnsond7720632016-10-05 16:04:32 -07006260static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08006261{
6262 struct ipa_uc_pending_event *pending_event = NULL;
6263
Anurag Chouhanffb21542016-02-17 14:33:03 +05306264 while (qdf_list_remove_front(&hdd_ipa->pending_event,
6265 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306266 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08006267 }
6268
Anurag Chouhanffb21542016-02-17 14:33:03 +05306269 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08006270}
6271
6272/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006273 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006274 * @hdd_ctx: HDD global context
6275 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306276 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006277 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006278static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006279{
6280 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
6281 int i;
6282 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05306283 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006284 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
6285
6286 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306287 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006288
6289 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
6290 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
6291 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6292 }
6293
6294 /* Teardown IPA sys_pipe for MCC */
6295 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
6296 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6297
6298 hdd_ipa_destroy_rm_resource(hdd_ipa);
6299
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006300 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006301
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306302 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006303
Nirav Shahcbc6d722016-03-01 16:24:53 +05306304 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
6305 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306306 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006307
6308 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07006309 if (pm_tx_cb->ipa_tx_desc)
6310 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006311
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306312 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006313 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306314 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006315
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306316 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006317 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006318
6319 /* destory the interface lock */
6320 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6321 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306322 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006323 }
6324
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006325 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08006326 if (ipa_uc_dereg_rdyCB())
6327 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
6328 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006329 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306330 qdf_mutex_destroy(&hdd_ipa->event_lock);
6331 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08006332 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006333
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006334 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6335 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
6336 hdd_ipa->uc_op_work[i].msg = NULL;
6337 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006338 }
6339
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306340 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006341 hdd_ctx->hdd_ipa = NULL;
6342
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306343 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006344}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006345
6346/**
6347 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
6348 * @hdd_ctx: HDD global context
6349 *
6350 * Return: QDF_STATUS enumeration
6351 */
6352QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
6353{
6354 QDF_STATUS ret;
6355
6356 cds_ssr_protect(__func__);
6357 ret = __hdd_ipa_cleanup(hdd_ctx);
6358 cds_ssr_unprotect(__func__);
6359
6360 return ret;
6361}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006362#endif /* IPA_OFFLOAD */