blob: ab68a04c75c8f93fc58f66e21ac19bcec64ea27b [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
jge62037862016-12-09 10:44:33 +08002 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ipa.c
30 *
31 * WLAN HDD and ipa interface implementation
32 * Originally written by Qualcomm Atheros, Inc
33 */
34
35#ifdef IPA_OFFLOAD
36
37/* Include Files */
Dustin Brown0bec9a92017-08-17 15:44:34 -070038#include <linux/ipa.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039#include <wlan_hdd_includes.h>
40#include <wlan_hdd_ipa.h>
41
42#include <linux/etherdevice.h>
43#include <linux/atomic.h>
44#include <linux/netdevice.h>
45#include <linux/skbuff.h>
46#include <linux/list.h>
47#include <linux/debugfs.h>
48#include <linux/inetdevice.h>
49#include <linux/ip.h>
50#include <wlan_hdd_softap_tx_rx.h>
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +053051#include <ol_txrx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070052#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053
54#include "cds_sched.h"
55
56#include "wma.h"
57#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080058#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
Dhanashri Atreb08959a2016-03-01 17:28:03 -080060#include "cdp_txrx_ipa.h"
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -080061#include "wlan_policy_mgr_api.h"
62
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080063#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080064#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
Yun Parkb4f591d2017-03-29 15:51:01 -070065
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080066#define HDD_IPA_UC_NUM_WDI_PIPE 2
67#define HDD_IPA_UC_MAX_PENDING_EVENT 33
68
69#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
70#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
71#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
72#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
73
74#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
75#define HDD_IPA_MAX_IFACE 3
76#define HDD_IPA_MAX_SYSBAM_PIPE 4
Yun Parkb4f591d2017-03-29 15:51:01 -070077
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080078#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
79#define HDD_IPA_ENABLE_MASK BIT(0)
80#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
81#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
82#define HDD_IPA_RM_ENABLE_MASK BIT(3)
83#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
84#define HDD_IPA_UC_ENABLE_MASK BIT(5)
85#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
86#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
87
Yun Parkf19e07d2015-11-20 11:34:27 -080088#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
89
tfyu0380a972017-07-13 18:19:37 +080090#define IPA_WLAN_RX_SOFTIRQ_THRESH 16
91
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -070092enum hdd_ipa_uc_op_code {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080093 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
94 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
95 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
96 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
97 HDD_IPA_UC_OPCODE_STATS = 4,
Yun Park637d6482016-10-05 10:51:33 -070098#ifdef FEATURE_METERING
99 HDD_IPA_UC_OPCODE_SHARING_STATS = 5,
100 HDD_IPA_UC_OPCODE_QUOTA_RSP = 6,
101 HDD_IPA_UC_OPCODE_QUOTA_IND = 7,
102#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800103 HDD_IPA_UC_OPCODE_UC_READY = 8,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800104 /* keep this last */
105 HDD_IPA_UC_OPCODE_MAX
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700106};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800107
108/**
109 * enum - Reason codes for stat query
110 *
111 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
112 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
113 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800114 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800115 */
116enum {
117 HDD_IPA_UC_STAT_REASON_NONE,
118 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -0800119 HDD_IPA_UC_STAT_REASON_BW_CAL,
120 HDD_IPA_UC_STAT_REASON_DUMP_INFO
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800121};
122
123/**
124 * enum hdd_ipa_rm_state - IPA resource manager state
125 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
126 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
127 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
128 */
129enum hdd_ipa_rm_state {
130 HDD_IPA_RM_RELEASED,
131 HDD_IPA_RM_GRANT_PENDING,
132 HDD_IPA_RM_GRANTED,
133};
134
135struct llc_snap_hdr {
136 uint8_t dsap;
137 uint8_t ssap;
138 uint8_t resv[4];
139 __be16 eth_type;
140} __packed;
141
Leo Chang3bc8fed2015-11-13 10:59:47 -0800142/**
143 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
144 * @eth: ether II header
145 * @llc_snap: LLC snap header
146 *
147 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800148struct hdd_ipa_tx_hdr {
149 struct ethhdr eth;
150 struct llc_snap_hdr llc_snap;
151} __packed;
152
Leo Chang3bc8fed2015-11-13 10:59:47 -0800153/**
154 * struct frag_header - fragment header type registered to IPA hardware
155 * @length: fragment length
156 * @reserved1: Reserved not used
157 * @reserved2: Reserved not used
158 *
159 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800160struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800161 uint16_t length;
162 uint32_t reserved1;
163 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164} __packed;
165
Leo Chang3bc8fed2015-11-13 10:59:47 -0800166/**
167 * struct ipa_header - ipa header type registered to IPA hardware
168 * @vdev_id: vdev id
169 * @reserved: Reserved not used
170 *
171 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800172struct ipa_header {
173 uint32_t
174 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
175 reserved:24;
176} __packed;
177
Leo Chang3bc8fed2015-11-13 10:59:47 -0800178/**
179 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
180 * @frag_hd: fragment header
181 * @ipa_hd: ipa header
182 * @eth: ether II header
183 *
184 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185struct hdd_ipa_uc_tx_hdr {
186 struct frag_header frag_hd;
187 struct ipa_header ipa_hd;
188 struct ethhdr eth;
189} __packed;
190
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800191/**
192 * struct hdd_ipa_cld_hdr - IPA CLD Header
193 * @reserved: reserved fields
194 * @iface_id: interface ID
195 * @sta_id: Station ID
196 *
197 * Packed 32-bit structure
198 * +----------+----------+--------------+--------+
199 * | Reserved | QCMAP ID | interface id | STA ID |
200 * +----------+----------+--------------+--------+
201 */
202struct hdd_ipa_cld_hdr {
203 uint8_t reserved[2];
204 uint8_t iface_id;
205 uint8_t sta_id;
206} __packed;
207
208struct hdd_ipa_rx_hdr {
209 struct hdd_ipa_cld_hdr cld_hdr;
210 struct ethhdr eth;
211} __packed;
212
213struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700214 bool exception;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700215 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216 struct hdd_ipa_iface_context *iface_context;
217 struct ipa_rx_data *ipa_tx_desc;
218};
219
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800220struct hdd_ipa_sys_pipe {
221 uint32_t conn_hdl;
222 uint8_t conn_hdl_valid;
223 struct ipa_sys_connect_params ipa_sys_params;
224};
225
226struct hdd_ipa_iface_stats {
227 uint64_t num_tx;
228 uint64_t num_tx_drop;
229 uint64_t num_tx_err;
230 uint64_t num_tx_cac_drop;
231 uint64_t num_rx_prefilter;
232 uint64_t num_rx_ipa_excep;
233 uint64_t num_rx_recv;
234 uint64_t num_rx_recv_mul;
235 uint64_t num_rx_send_desc_err;
236 uint64_t max_rx_mul;
237};
238
239struct hdd_ipa_priv;
240
241struct hdd_ipa_iface_context {
242 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700243 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800244 void *tl_context;
245
246 enum ipa_client_type cons_client;
247 enum ipa_client_type prod_client;
248
249 uint8_t iface_id; /* This iface ID */
250 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530251 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800252 uint32_t ifa_address;
253 struct hdd_ipa_iface_stats stats;
254};
255
256struct hdd_ipa_stats {
257 uint32_t event[IPA_WLAN_EVENT_MAX];
258 uint64_t num_send_msg;
259 uint64_t num_free_msg;
260
261 uint64_t num_rm_grant;
262 uint64_t num_rm_release;
263 uint64_t num_rm_grant_imm;
264 uint64_t num_cons_perf_req;
265 uint64_t num_prod_perf_req;
266
267 uint64_t num_rx_drop;
268 uint64_t num_rx_ipa_tx_dp;
269 uint64_t num_rx_ipa_splice;
270 uint64_t num_rx_ipa_loop;
271 uint64_t num_rx_ipa_tx_dp_err;
272 uint64_t num_rx_ipa_write_done;
273 uint64_t num_max_ipa_tx_mul;
274 uint64_t num_rx_ipa_hw_maxed_out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800275
Yun Park52b2b992016-09-22 15:49:51 -0700276 uint64_t num_tx_desc_q_cnt;
277 uint64_t num_tx_desc_error;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800278 uint64_t num_tx_comp_cnt;
279 uint64_t num_tx_queued;
280 uint64_t num_tx_dequeued;
281 uint64_t num_max_pm_queue;
282
283 uint64_t num_freeq_empty;
284 uint64_t num_pri_freeq_empty;
285 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800286 uint64_t num_tx_fwd_ok;
287 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800288};
289
290struct ipa_uc_stas_map {
291 bool is_reserved;
292 uint8_t sta_id;
293};
294struct op_msg_type {
295 uint8_t msg_t;
296 uint8_t rsvd;
297 uint16_t op_code;
298 uint16_t len;
299 uint16_t rsvd_snd;
300};
301
302struct ipa_uc_fw_stats {
303 uint32_t tx_comp_ring_base;
304 uint32_t tx_comp_ring_size;
305 uint32_t tx_comp_ring_dbell_addr;
306 uint32_t tx_comp_ring_dbell_ind_val;
307 uint32_t tx_comp_ring_dbell_cached_val;
308 uint32_t tx_pkts_enqueued;
309 uint32_t tx_pkts_completed;
310 uint32_t tx_is_suspend;
311 uint32_t tx_reserved;
312 uint32_t rx_ind_ring_base;
313 uint32_t rx_ind_ring_size;
314 uint32_t rx_ind_ring_dbell_addr;
315 uint32_t rx_ind_ring_dbell_ind_val;
316 uint32_t rx_ind_ring_dbell_ind_cached_val;
317 uint32_t rx_ind_ring_rdidx_addr;
318 uint32_t rx_ind_ring_rd_idx_cached_val;
319 uint32_t rx_refill_idx;
320 uint32_t rx_num_pkts_indicated;
321 uint32_t rx_buf_refilled;
322 uint32_t rx_num_ind_drop_no_space;
323 uint32_t rx_num_ind_drop_no_buf;
324 uint32_t rx_is_suspend;
325 uint32_t rx_reserved;
326};
327
328struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530329 qdf_list_node_t node;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700330 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800331 enum ipa_wlan_event type;
332 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530333 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800334};
335
336/**
337 * struct uc_rm_work_struct
338 * @work: uC RM work
339 * @event: IPA RM event
340 */
341struct uc_rm_work_struct {
342 struct work_struct work;
343 enum ipa_rm_event event;
344};
345
346/**
347 * struct uc_op_work_struct
348 * @work: uC OP work
349 * @msg: OP message
350 */
351struct uc_op_work_struct {
352 struct work_struct work;
353 struct op_msg_type *msg;
354};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800355
356/**
357 * struct uc_rt_debug_info
358 * @time: system time
359 * @ipa_excep_count: IPA exception packet count
360 * @rx_drop_count: IPA Rx drop packet count
361 * @net_sent_count: IPA Rx packet sent to network stack count
362 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800363 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800364 * @tx_fwd_count: IPA Tx forward packet count
365 * @rx_destructor_call: IPA Rx packet destructor count
366 */
367struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530368 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800369 uint64_t ipa_excep_count;
370 uint64_t rx_drop_count;
371 uint64_t net_sent_count;
372 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800373 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800374 uint64_t tx_fwd_count;
375 uint64_t rx_destructor_call;
376};
377
Yun Park637d6482016-10-05 10:51:33 -0700378#ifdef FEATURE_METERING
379struct ipa_uc_sharing_stats {
380 uint64_t ipv4_rx_packets;
381 uint64_t ipv4_rx_bytes;
382 uint64_t ipv6_rx_packets;
383 uint64_t ipv6_rx_bytes;
384 uint64_t ipv4_tx_packets;
385 uint64_t ipv4_tx_bytes;
386 uint64_t ipv6_tx_packets;
387 uint64_t ipv6_tx_bytes;
388};
389
390struct ipa_uc_quota_rsp {
391 uint8_t success;
392 uint8_t reserved[3];
393 uint32_t quota_lo; /* quota limit low bytes */
394 uint32_t quota_hi; /* quota limit high bytes */
395};
396
397struct ipa_uc_quota_ind {
398 uint64_t quota_bytes; /* quota limit in bytes */
399};
400#endif
401
Yun Park52b2b992016-09-22 15:49:51 -0700402/**
403 * struct hdd_ipa_tx_desc
404 * @link: link to list head
405 * @priv: pointer to priv list entry
406 * @id: Tx desc idex
407 * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor
408 */
409struct hdd_ipa_tx_desc {
410 struct list_head link;
411 void *priv;
412 uint32_t id;
413 struct ipa_rx_data *ipa_tx_desc_ptr;
414};
415
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800416struct hdd_ipa_priv {
417 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
418 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
419 uint8_t num_iface;
420 enum hdd_ipa_rm_state rm_state;
421 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530422 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423 * APIs as it is taken care gracefully. Without this, kernel would throw
424 * an warning if spin_lock_bh is used while IRQ is disabled
425 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530426 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800427 struct uc_rm_work_struct uc_rm_work;
428 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530429 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800430 struct delayed_work wake_lock_work;
431 bool wake_lock_released;
432
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800433 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530434 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800435 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530436 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800437 bool suspended;
438
Yun Park52b2b992016-09-22 15:49:51 -0700439 qdf_spinlock_t q_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800440
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800441 struct list_head pend_desc_head;
jiad14fe4fb2017-08-08 13:33:14 +0800442 uint16_t tx_desc_size;
Yun Park52b2b992016-09-22 15:49:51 -0700443 struct hdd_ipa_tx_desc *tx_desc_list;
444 struct list_head free_tx_desc_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800445
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700446 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800447
448 struct dentry *debugfs_dir;
449 struct hdd_ipa_stats stats;
450
451 struct notifier_block ipv4_notifier;
452 uint32_t curr_prod_bw;
453 uint32_t curr_cons_bw;
454
455 uint8_t activated_fw_pipe;
456 uint8_t sap_num_connected_sta;
457 uint8_t sta_connected;
458 uint32_t tx_pipe_handle;
459 uint32_t rx_pipe_handle;
460 bool resource_loading;
461 bool resource_unloading;
462 bool pending_cons_req;
463 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530464 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530465 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700466 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800467 uint32_t ipa_tx_packets_diff;
468 uint32_t ipa_rx_packets_diff;
469 uint32_t ipa_p_tx_packets;
470 uint32_t ipa_p_rx_packets;
471 uint32_t stat_req_reason;
472 uint64_t ipa_tx_forward;
473 uint64_t ipa_rx_discard;
474 uint64_t ipa_rx_net_send_count;
475 uint64_t ipa_rx_internel_drop_count;
476 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530477 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800478 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
479 unsigned int rt_buf_fill_index;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800480 struct ipa_wdi_in_params cons_pipe_in;
481 struct ipa_wdi_in_params prod_pipe_in;
482 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800483 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530484 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530485 qdf_mutex_t rt_debug_lock;
486 qdf_mutex_t ipa_lock;
Yun Parkb4f591d2017-03-29 15:51:01 -0700487
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800488 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
489 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Yun Park637d6482016-10-05 10:51:33 -0700490#ifdef FEATURE_METERING
491 struct ipa_uc_sharing_stats ipa_sharing_stats;
492 struct ipa_uc_quota_rsp ipa_quota_rsp;
493 struct ipa_uc_quota_ind ipa_quota_ind;
494 struct completion ipa_uc_sharing_stats_comp;
495 struct completion ipa_uc_set_quota_comp;
496#endif
Yun Park777d7242017-03-30 15:38:33 -0700497 struct completion ipa_resource_comp;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800498};
499
Leo Changcc923e22016-06-16 15:29:03 -0700500#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
501#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800502#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
503#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
504#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
505#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
506#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700507#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
508 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800509
510#define HDD_IPA_GET_IFACE_ID(_data) \
511 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
512
513#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530514 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800515 "%s:%d: "fmt, __func__, __LINE__, ## args)
516
Govind Singhb6a89772016-08-12 11:23:35 +0530517#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
518 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
519 "%s:%d: "fmt, __func__, __LINE__, ## args)
520
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800521#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
522 do { \
Yun Parkec845302016-12-15 09:22:57 -0800523 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \
524 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525 } while (0)
526
527#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
528 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
529
530#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
Jeff Johnsond5ba8a62017-09-30 14:30:53 -0700531 (hdd_ipa)->ipa_rx_internel_drop_count++
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800532#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
Jeff Johnsond5ba8a62017-09-30 14:30:53 -0700533 (hdd_ipa)->ipa_rx_net_send_count++
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800534#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
535
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700536#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)
Leo Chang63d73612016-10-18 18:09:43 -0700537#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800538#else
539/* Do nothing */
Leo Chang63d73612016-10-18 18:09:43 -0700540#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700541#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800542
Yun Parkb187d542016-11-14 18:10:04 -0800543#define HDD_IPA_DBG_DUMP_RX_LEN 32
544#define HDD_IPA_DBG_DUMP_TX_LEN 48
545
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800546static struct hdd_ipa_adapter_2_client {
547 enum ipa_client_type cons_client;
548 enum ipa_client_type prod_client;
549} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
550 {
551 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
552 }, {
553 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
554 }, {
555 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
556 },
557};
558
Yun Park637d6482016-10-05 10:51:33 -0700559#ifdef FEATURE_METERING
560#define IPA_UC_SHARING_STATES_WAIT_TIME 500
561#define IPA_UC_SET_QUOTA_WAIT_TIME 500
562#endif
563
Yun Park777d7242017-03-30 15:38:33 -0700564#define IPA_RESOURCE_COMP_WAIT_TIME 100
565
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800566static struct hdd_ipa_priv *ghdd_ipa;
567
568/* Local Function Prototypes */
569static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
570 unsigned long data);
571static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
572 unsigned long data);
Yun Parkb4f591d2017-03-29 15:51:01 -0700573#ifdef FEATURE_METERING
574static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
575 void *data);
576#else
577static void hdd_ipa_wdi_meter_notifier_cb(void);
578#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800579static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800580
581static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700582static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800583
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800584#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
585 defined(IPA_CLIENT_IS_MHI_CONS))
586/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800587 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
588 * @priv_ctxt: hdd ipa local context
589 *
590 * Will be called by IPA context.
591 * It's atomic context, then should be scheduled to kworker thread
592 *
593 * Return: None
594 */
595static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
596{
597 struct hdd_ipa_priv *hdd_ipa;
598 struct op_msg_type *msg;
599 struct uc_op_work_struct *uc_op_work;
600
601 if (priv_ctxt == NULL) {
602 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
603 return;
604 }
605
606 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
607 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
608 if (!msg) {
609 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
610 return;
611 }
612
613 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
614
615 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
616
617 /* When the same uC OPCODE is already pended, just return */
618 if (uc_op_work->msg)
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530619 goto done;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800620
621 uc_op_work->msg = msg;
622 schedule_work(&uc_op_work->work);
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530623
jiadd91a6842017-08-01 14:46:02 +0800624 /* work handler will free the msg buffer */
625 return;
626
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530627done:
628 qdf_mem_free(msg);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800629}
630
631/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800632 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
633 * @ctrl: WDI control value
634 *
635 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
636 *
637 * Return: 0 on message send to ipa, -1 on failure
638 */
639static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
640{
641 struct ipa_msg_meta meta;
642 struct ipa_wlan_msg *ipa_msg;
643 int ret = 0;
644
645 /* WDI enable message to IPA */
646 meta.msg_len = sizeof(*ipa_msg);
647 ipa_msg = qdf_mem_malloc(meta.msg_len);
648 if (ipa_msg == NULL) {
649 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
650 "msg allocation failed");
651 return -ENOMEM;
652 }
653
654 if (ctrl == true)
655 meta.msg_type = WLAN_WDI_ENABLE;
656 else
657 meta.msg_type = WLAN_WDI_DISABLE;
658
Srinivas Girigowda97852372017-03-06 16:52:59 -0800659 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800660 "ipa_send_msg(Evt:%d)", meta.msg_type);
661 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
662 if (ret) {
663 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
664 "ipa_send_msg(Evt:%d)-fail=%d",
665 meta.msg_type, ret);
666 qdf_mem_free(ipa_msg);
667 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800668 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800669}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800670
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800671/**
672 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
673 * @hdd_ipa: HDD IPA local context
674 *
675 * Register IPA UC ready callback function to IPA kernel driver
676 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
677 * open WDI pipe after WLAN driver loading finished
678 *
679 * Return: 0 Success
680 * -EPERM Registration fail
681 */
682static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
683{
684 struct ipa_wdi_uc_ready_params uc_ready_param;
685 int ret = 0;
686
687 hdd_ipa->uc_loaded = false;
688 uc_ready_param.priv = (void *)hdd_ipa;
689 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
690 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
691 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
692 "UC Ready CB register fail");
693 return -EPERM;
694 }
695 if (true == uc_ready_param.is_uC_ready) {
Srinivas Girigowda2b5d47c2017-03-29 00:28:46 -0700696 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800697 hdd_ipa->uc_loaded = true;
698 } else {
699 ret = hdd_ipa_uc_send_wdi_control_msg(false);
700 }
701
702 return ret;
703}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800704#else
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800705static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
706{
707 hdd_ipa->uc_loaded = true;
708 return 0;
709}
710
711static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
712{
713 return 0;
714}
715#endif
716
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800717/**
718 * hdd_ipa_is_enabled() - Is IPA enabled?
719 * @hdd_ctx: Global HDD context
720 *
721 * Return: true if IPA is enabled, false otherwise
722 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700723bool hdd_ipa_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800724{
725 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
726}
727
728/**
729 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
730 * @hdd_ctx: Global HDD context
731 *
732 * Return: true if IPA uC offload is enabled, false otherwise
733 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700734bool hdd_ipa_uc_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800735{
736 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
737}
738
739/**
740 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
741 * @hdd_ctx: Global HDD context
742 *
743 * Return: true if STA mode IPA uC offload is enabled, false otherwise
744 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700745static inline bool hdd_ipa_uc_sta_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800746{
747 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
748}
749
750/**
Guolei Bianca144d82016-11-10 11:07:42 +0800751 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
752 * @hdd_ipa: Global HDD IPA context
753 *
754 * Return: None
755 */
Guolei Bianca144d82016-11-10 11:07:42 +0800756static inline void hdd_ipa_uc_sta_reset_sta_connected(
757 struct hdd_ipa_priv *hdd_ipa)
758{
Yun Park637d6482016-10-05 10:51:33 -0700759 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800760 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700761 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800762}
Guolei Bianca144d82016-11-10 11:07:42 +0800763
764/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800765 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
766 * @hdd_ipa: Global HDD IPA context
767 *
768 * Return: true if pre-filter is enabled, otherwise false
769 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700770static inline bool hdd_ipa_is_pre_filter_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800771{
772 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
773 HDD_IPA_PRE_FILTER_ENABLE_MASK);
774}
775
776/**
777 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
778 * @hdd_ipa: Global HDD IPA context
779 *
780 * Return: true if IPv6 is enabled, otherwise false
781 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700782static inline bool hdd_ipa_is_ipv6_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800783{
784 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
785}
786
787/**
788 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
789 * @hdd_ipa: Global HDD IPA context
790 *
791 * Return: true if resource manager is enabled, otherwise false
792 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700793static inline bool hdd_ipa_is_rm_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800794{
795 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
796}
797
798/**
799 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
800 * @hdd_ipa: Global HDD IPA context
801 *
802 * Return: true if resource manager is enabled, otherwise false
803 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700804static inline bool hdd_ipa_is_rt_debugging_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800805{
806 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
807}
808
809/**
810 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
811 * @hdd_ipa: Global HDD IPA context
812 *
813 * Return: true if clock scaling is enabled, otherwise false
814 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700815static inline bool hdd_ipa_is_clk_scaling_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800816{
817 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
818 HDD_IPA_CLK_SCALING_ENABLE_MASK |
819 HDD_IPA_RM_ENABLE_MASK);
820}
821
822/**
823 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
824 * @ctext: pointer to hdd context.
825 *
826 * If rt debug enabled, periodically called, and fill debug buffer
827 *
828 * Return: none
829 */
830static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
831{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700832 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833 struct hdd_ipa_priv *hdd_ipa;
834 struct uc_rt_debug_info *dump_info = NULL;
835
836 if (wlan_hdd_validate_context(hdd_ctx))
837 return;
838
839 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700840 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800841 return;
842 }
843
844 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
845
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530846 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847 dump_info = &hdd_ipa->rt_bug_buffer[
848 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
849
Deepthi Gowri6acee342016-10-28 15:00:38 +0530850 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800851 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
852 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
853 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800855 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
856 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800857 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
858 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530859 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800860
Anurag Chouhan210db072016-02-22 18:42:15 +0530861 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800862 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
863}
864
865/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700866 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800867 * @hdd_ctx: pointer to hdd context.
868 *
869 * If rt debug enabled, dump debug buffer contents based on requirement
870 *
871 * Return: none
872 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700873static void __hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800874{
875 struct hdd_ipa_priv *hdd_ipa;
876 unsigned int dump_count;
877 unsigned int dump_index;
878 struct uc_rt_debug_info *dump_info = NULL;
879
880 if (wlan_hdd_validate_context(hdd_ctx))
881 return;
882
883 hdd_ipa = hdd_ctx->hdd_ipa;
884 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700885 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800886 return;
887 }
888
Chris Guo1751acf2017-07-03 14:09:01 +0800889 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
890 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
891 "%s: IPA RT debug is not enabled", __func__);
892 return;
893 }
894
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530895 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530897 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800898 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530900 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800901 for (dump_count = 0;
902 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
903 dump_count++) {
904 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
905 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
906 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530907 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530908 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800909 dump_info->time, dump_info->ipa_excep_count,
910 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800911 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800912 dump_info->rx_destructor_call,
913 dump_info->rx_discard_count);
914 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530915 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530916 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
918}
919
920/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700921 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
922 * __hdd_ipa_uc_rt_debug_host_dump
923 * @hdd_ctx: pointer to hdd context.
924 *
925 * If rt debug enabled, dump debug buffer contents based on requirement
926 *
927 * Return: none
928 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700929void hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700930{
931 cds_ssr_protect(__func__);
932 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
933 cds_ssr_unprotect(__func__);
934}
935
936/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800937 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
938 * @ctext: pointer to hdd context.
939 *
940 * periodically called by timer expire
941 * will try to alloc dummy memory and detect out of memory condition
942 * if out of memory detected, dump wlan-ipa stats
943 *
944 * Return: none
945 */
946static void hdd_ipa_uc_rt_debug_handler(void *ctext)
947{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700948 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700949 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800950 void *dummy_ptr = NULL;
951
952 if (wlan_hdd_validate_context(hdd_ctx))
953 return;
954
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700955 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
956
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800957 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700958 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
959 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800960 return;
961 }
962
963 /* Allocate dummy buffer periodically and free immediately. this will
964 * proactively detect OOM and if allocation fails dump ipa stats
965 */
966 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
967 GFP_KERNEL | GFP_ATOMIC);
968 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800969 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
970 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -0700971 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
972 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973 } else {
974 kfree(dummy_ptr);
975 }
976
Anurag Chouhan210db072016-02-22 18:42:15 +0530977 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800978 HDD_IPA_UC_RT_DEBUG_PERIOD);
979}
980
981/**
Yun Parkb187d542016-11-14 18:10:04 -0800982 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800983 * @skb: packet pinter
984 *
985 * when free data packet, will be invoked by wlan client and will increase
986 * free counter
987 *
988 * Return: none
989 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700990static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800991{
992 if (!ghdd_ipa) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700993 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "invalid hdd context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994 return;
995 }
996
997 ghdd_ipa->ipa_rx_destructor_count++;
998}
999
1000/**
Yun Parkb187d542016-11-14 18:10:04 -08001001 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001002 * @hdd_ctx: hdd main context
1003 *
1004 * free all rt debugging resources
1005 *
1006 * Return: none
1007 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001008static void hdd_ipa_uc_rt_debug_deinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001009{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001010 struct hdd_ipa_priv *hdd_ipa;
1011
1012 if (wlan_hdd_validate_context(hdd_ctx))
1013 return;
1014
1015 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001016
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301017 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001018
1019 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001020 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1021 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001022 return;
1023 }
1024
Anurag Chouhan210db072016-02-22 18:42:15 +05301025 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001026 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1027 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1028 }
1029 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1030
1031 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301032 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1033 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301035 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001036}
1037
1038/**
Yun Parkb187d542016-11-14 18:10:04 -08001039 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001040 * @hdd_ctx: hdd main context
1041 *
1042 * alloc and initialize all rt debugging resources
1043 *
1044 * Return: none
1045 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001046static void hdd_ipa_uc_rt_debug_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001047{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001048 struct hdd_ipa_priv *hdd_ipa;
1049
Chris Guo1751acf2017-07-03 14:09:01 +08001050 if (wlan_hdd_validate_context_in_loading(hdd_ctx))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001051 return;
1052
1053 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301055 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001056 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301057 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001058 sizeof(struct uc_rt_debug_info) *
1059 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1060 hdd_ipa->ipa_tx_forward = 0;
1061 hdd_ipa->ipa_rx_discard = 0;
1062 hdd_ipa->ipa_rx_net_send_count = 0;
1063 hdd_ipa->ipa_rx_internel_drop_count = 0;
1064 hdd_ipa->ipa_rx_destructor_count = 0;
1065
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001066 /* Reatime debug enable on feature enable */
1067 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001068 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1069 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001070 return;
1071 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001072
1073 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1074 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1075 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1076 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1077
Anurag Chouhan210db072016-02-22 18:42:15 +05301078 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001079 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301080 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001081 HDD_IPA_UC_RT_DEBUG_PERIOD);
1082
1083}
1084
1085/**
Yun Parkb187d542016-11-14 18:10:04 -08001086 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1087 * @hdd_ipa: HDD IPA struct
1088 *
1089 * Dump entries in struct hdd_ipa
1090 *
1091 * Return: none
1092 */
1093static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1094{
1095 int i;
1096
1097 /* HDD IPA */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001098 hdd_info("==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001099 "num_iface: %d\n"
1100 "rm_state: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001101 "rm_lock: %pK\n"
1102 "uc_rm_work: %pK\n"
1103 "uc_op_work: %pK\n"
1104 "wake_lock: %pK\n"
1105 "wake_lock_work: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001106 "wake_lock_released: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001107 "tx_ref_cnt: %d\n"
1108 "pm_queue_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001109 "\thead: %pK\n"
1110 "\ttail: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001111 "\tqlen: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001112 "pm_work: %pK\n"
1113 "pm_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001114 "suspended: %d\n",
1115 hdd_ipa->num_iface,
1116 hdd_ipa->rm_state,
1117 &hdd_ipa->rm_lock,
1118 &hdd_ipa->uc_rm_work,
1119 &hdd_ipa->uc_op_work,
1120 &hdd_ipa->wake_lock,
1121 &hdd_ipa->wake_lock_work,
1122 hdd_ipa->wake_lock_released,
Yun Parkb187d542016-11-14 18:10:04 -08001123 hdd_ipa->tx_ref_cnt.counter,
1124 hdd_ipa->pm_queue_head.head,
1125 hdd_ipa->pm_queue_head.tail,
1126 hdd_ipa->pm_queue_head.qlen,
1127 &hdd_ipa->pm_work,
1128 &hdd_ipa->pm_lock,
1129 hdd_ipa->suspended);
Jeff Johnson36e74c42017-09-18 08:15:42 -07001130 hdd_err("\nq_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001131 "pend_desc_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001132 "\tnext: %pK\n"
1133 "\tprev: %pK\n"
1134 "hdd_ctx: %pK\n"
1135 "debugfs_dir: %pK\n"
1136 "stats: %pK\n"
1137 "ipv4_notifier: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001138 "curr_prod_bw: %d\n"
1139 "curr_cons_bw: %d\n"
1140 "activated_fw_pipe: %d\n"
1141 "sap_num_connected_sta: %d\n"
1142 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001143 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001144 hdd_ipa->pend_desc_head.next,
1145 hdd_ipa->pend_desc_head.prev,
1146 hdd_ipa->hdd_ctx,
1147 hdd_ipa->debugfs_dir,
1148 &hdd_ipa->stats,
1149 &hdd_ipa->ipv4_notifier,
1150 hdd_ipa->curr_prod_bw,
1151 hdd_ipa->curr_cons_bw,
1152 hdd_ipa->activated_fw_pipe,
1153 hdd_ipa->sap_num_connected_sta,
1154 (unsigned int)hdd_ipa->sta_connected
1155 );
Srinivas Girigowda97852372017-03-06 16:52:59 -08001156 hdd_info("\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001157 "rx_pipe_handle: 0x%x\n"
1158 "resource_loading: %d\n"
1159 "resource_unloading: %d\n"
1160 "pending_cons_req: %d\n"
1161 "pending_event----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001162 "\tanchor.next: %pK\n"
1163 "\tanchor.prev: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001164 "\tcount: %d\n"
1165 "\tmax_size: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001166 "event_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001167 "ipa_tx_packets_diff: %d\n"
1168 "ipa_rx_packets_diff: %d\n"
1169 "ipa_p_tx_packets: %d\n"
1170 "ipa_p_rx_packets: %d\n"
1171 "stat_req_reason: %d\n",
1172 hdd_ipa->tx_pipe_handle,
1173 hdd_ipa->rx_pipe_handle,
1174 hdd_ipa->resource_loading,
1175 hdd_ipa->resource_unloading,
1176 hdd_ipa->pending_cons_req,
1177 hdd_ipa->pending_event.anchor.next,
1178 hdd_ipa->pending_event.anchor.prev,
1179 hdd_ipa->pending_event.count,
1180 hdd_ipa->pending_event.max_size,
1181 &hdd_ipa->event_lock,
1182 hdd_ipa->ipa_tx_packets_diff,
1183 hdd_ipa->ipa_rx_packets_diff,
1184 hdd_ipa->ipa_p_tx_packets,
1185 hdd_ipa->ipa_p_rx_packets,
1186 hdd_ipa->stat_req_reason);
1187
Srinivas Girigowda97852372017-03-06 16:52:59 -08001188 hdd_info("assoc_stas_map([id]is_reserved/sta_id): ");
Yun Parkb187d542016-11-14 18:10:04 -08001189 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08001190 hdd_info(" [%d]%d/%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001191 hdd_ipa->assoc_stas_map[i].is_reserved,
1192 hdd_ipa->assoc_stas_map[i].sta_id);
1193 }
1194}
1195
1196/**
1197 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1198 * @hdd_ipa: HDD IPA struct
1199 *
1200 * Dump entire struct hdd_ipa_sys_pipe
1201 *
1202 * Return: none
1203 */
1204static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1205{
1206 int i;
1207
1208 /* IPA SYS Pipes */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001209 hdd_info("==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001210
1211 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1212 struct hdd_ipa_sys_pipe *sys_pipe;
1213 struct ipa_sys_connect_params *ipa_sys_params;
1214
1215 sys_pipe = &hdd_ipa->sys_pipe[i];
1216 ipa_sys_params = &sys_pipe->ipa_sys_params;
1217
Srinivas Girigowda97852372017-03-06 16:52:59 -08001218 hdd_info("sys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001219 "\tconn_hdl: 0x%x\n"
1220 "\tconn_hdl_valid: %d\n"
1221 "\tnat_en: %d\n"
1222 "\thdr_len %d\n"
1223 "\thdr_additional_const_len: %d\n"
1224 "\thdr_ofst_pkt_size_valid: %d\n"
1225 "\thdr_ofst_pkt_size: %d\n"
1226 "\thdr_little_endian: %d\n"
1227 "\tmode: %d\n"
1228 "\tclient: %d\n"
1229 "\tdesc_fifo_sz: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001230 "\tpriv: %pK\n"
1231 "\tnotify: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001232 "\tskip_ep_cfg: %d\n"
1233 "\tkeep_ipa_awake: %d\n",
1234 i,
1235 sys_pipe->conn_hdl,
1236 sys_pipe->conn_hdl_valid,
1237 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1238 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1239 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1240 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1241 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1242 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1243 ipa_sys_params->ipa_ep_cfg.mode.mode,
1244 ipa_sys_params->client,
1245 ipa_sys_params->desc_fifo_sz,
1246 ipa_sys_params->priv,
1247 ipa_sys_params->notify,
1248 ipa_sys_params->skip_ep_cfg,
1249 ipa_sys_params->keep_ipa_awake);
1250 }
1251}
1252
1253/**
1254 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1255 * @hdd_ipa: HDD IPA struct
1256 *
1257 * Dump entire struct hdd_ipa_iface_context
1258 *
1259 * Return: none
1260 */
1261static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1262{
1263 int i;
1264
1265 /* IPA Interface Contexts */
Srinivas Girigowda97852372017-03-06 16:52:59 -08001266 hdd_info("==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001267
1268 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1269 struct hdd_ipa_iface_context *iface_context;
1270
1271 iface_context = &hdd_ipa->iface_context[i];
1272
Srinivas Girigowda97852372017-03-06 16:52:59 -08001273 hdd_info("iface_context[%d]----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001274 "\thdd_ipa: %pK\n"
1275 "\tadapter: %pK\n"
1276 "\ttl_context: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001277 "\tcons_client: %d\n"
1278 "\tprod_client: %d\n"
1279 "\tiface_id: %d\n"
1280 "\tsta_id: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001281 "\tinterface_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001282 "\tifa_address: 0x%x\n",
1283 i,
1284 iface_context->hdd_ipa,
1285 iface_context->adapter,
1286 iface_context->tl_context,
1287 iface_context->cons_client,
1288 iface_context->prod_client,
1289 iface_context->iface_id,
1290 iface_context->sta_id,
1291 &iface_context->interface_lock,
1292 iface_context->ifa_address);
1293 }
1294}
1295
1296/**
1297 * hdd_ipa_dump_info() - dump HDD IPA struct
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001298 * @hdd_ctx: hdd main context
Yun Parkb187d542016-11-14 18:10:04 -08001299 *
1300 * Dump entire struct hdd_ipa
1301 *
1302 * Return: none
1303 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001304void hdd_ipa_dump_info(struct hdd_context *hdd_ctx)
Yun Parkb187d542016-11-14 18:10:04 -08001305{
1306 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1307
1308 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1309 hdd_ipa_dump_sys_pipe(hdd_ipa);
1310 hdd_ipa_dump_iface_context(hdd_ipa);
1311}
1312
1313/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001314 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1315 * enabled
1316 *
1317 * This routine is called to set TX flow info if IPA is enabled
1318 *
1319 * Return: None
1320 */
1321void hdd_ipa_set_tx_flow_info(void)
1322{
1323 hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL;
1324 QDF_STATUS status;
Jeff Johnson49d45e62017-08-29 14:30:42 -07001325 struct hdd_adapter *adapter;
Jeff Johnsond377dce2017-10-04 10:32:42 -07001326 struct hdd_station_ctx *sta_ctx;
Jeff Johnson87251032017-08-29 13:31:11 -07001327 struct hdd_ap_ctx *hdd_ap_ctx;
Jeff Johnsonca2530c2017-09-30 18:25:40 -07001328 struct hdd_hostapd_state *hostapd_state;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001329 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1330 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1331 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1332 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1333 const char *p2pMode = "DEV";
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001334 struct hdd_context *hdd_ctx;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001335 cds_context_type *cds_ctx;
1336#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1337 uint8_t targetChannel = 0;
1338 uint8_t preAdapterChannel = 0;
1339 uint8_t channel24;
1340 uint8_t channel5;
Jeff Johnson49d45e62017-08-29 14:30:42 -07001341 struct hdd_adapter *preAdapterContext = NULL;
1342 struct hdd_adapter *adapter2_4 = NULL;
1343 struct hdd_adapter *adapter5 = NULL;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001344 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1345#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1346 struct wlan_objmgr_psoc *psoc;
1347
1348 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1349 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001350 hdd_err("HDD context is NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001351 return;
1352 }
1353
1354 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1355 if (!cds_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001356 hdd_err("Invalid CDS Context");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001357 return;
1358 }
1359
1360 psoc = hdd_ctx->hdd_psoc;
1361 status = hdd_get_front_adapter(hdd_ctx, &adapterNode);
1362 while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnson57eb2732017-10-02 11:40:20 -07001363 adapter = adapterNode->adapter;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001364 switch (adapter->device_mode) {
1365 case QDF_STA_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001366 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001367 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001368 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001369 staChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001370 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001371 qdf_copy_macaddr(&staBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001372 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001373#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1374 targetChannel = staChannel;
1375#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1376 }
1377 break;
1378 case QDF_P2P_CLIENT_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001379 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001380 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001381 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001382 p2pChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001383 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001384 qdf_copy_macaddr(&p2pBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001385 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001386 p2pMode = "CLI";
1387#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1388 targetChannel = p2pChannel;
1389#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1390 }
1391 break;
1392 case QDF_P2P_GO_MODE:
1393 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1394 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1395 if (hostapd_state->bssState == BSS_START
1396 && hostapd_state->qdf_status ==
1397 QDF_STATUS_SUCCESS) {
1398 p2pChannel = hdd_ap_ctx->operatingChannel;
1399 qdf_copy_macaddr(&p2pBssid,
1400 &adapter->macAddressCurrent);
1401#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1402 targetChannel = p2pChannel;
1403#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1404 }
1405 p2pMode = "GO";
1406 break;
1407 case QDF_SAP_MODE:
1408 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1409 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
1410 if (hostapd_state->bssState == BSS_START
1411 && hostapd_state->qdf_status ==
1412 QDF_STATUS_SUCCESS) {
1413 apChannel = hdd_ap_ctx->operatingChannel;
1414 qdf_copy_macaddr(&apBssid,
1415 &adapter->macAddressCurrent);
1416#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1417 targetChannel = apChannel;
1418#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1419 }
1420 break;
1421 case QDF_IBSS_MODE:
1422 default:
1423 break;
1424 }
1425#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1426 if (targetChannel) {
1427 /*
1428 * This is first adapter detected as active
1429 * set as default for none concurrency case
1430 */
1431 if (!preAdapterChannel) {
1432 /* If IPA UC data path is enabled,
1433 * target should reserve extra tx descriptors
1434 * for IPA data path.
1435 * Then host data path should allow less TX
1436 * packet pumping in case IPA
1437 * data path enabled
1438 */
1439 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1440 (QDF_SAP_MODE == adapter->device_mode)) {
1441 adapter->tx_flow_low_watermark =
1442 hdd_ctx->config->TxFlowLowWaterMark +
1443 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1444 } else {
1445 adapter->tx_flow_low_watermark =
1446 hdd_ctx->config->
1447 TxFlowLowWaterMark;
1448 }
1449 adapter->tx_flow_high_watermark_offset =
1450 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1451 cdp_fc_ll_set_tx_pause_q_depth(soc,
1452 adapter->sessionId,
1453 hdd_ctx->config->TxFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001454 hdd_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001455 adapter->device_mode,
1456 targetChannel,
1457 adapter->tx_flow_low_watermark,
1458 adapter->tx_flow_low_watermark +
1459 adapter->tx_flow_high_watermark_offset,
1460 hdd_ctx->config->TxFlowMaxQueueDepth);
1461 preAdapterChannel = targetChannel;
1462 preAdapterContext = adapter;
1463 } else {
1464 /*
1465 * SCC, disable TX flow control for both
1466 * SCC each adapter cannot reserve dedicated
1467 * channel resource, as a result, if any adapter
1468 * blocked OS Q by flow control,
1469 * blocked adapter will lost chance to recover
1470 */
1471 if (preAdapterChannel == targetChannel) {
1472 /* Current adapter */
1473 adapter->tx_flow_low_watermark = 0;
1474 adapter->
1475 tx_flow_high_watermark_offset = 0;
1476 cdp_fc_ll_set_tx_pause_q_depth(soc,
1477 adapter->sessionId,
1478 hdd_ctx->config->
1479 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001480 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001481 hdd_device_mode_to_string(
1482 adapter->device_mode),
1483 adapter->device_mode,
1484 targetChannel,
1485 adapter->tx_flow_low_watermark,
1486 adapter->tx_flow_low_watermark +
1487 adapter->
1488 tx_flow_high_watermark_offset,
1489 hdd_ctx->config->
1490 TxHbwFlowMaxQueueDepth);
1491
1492 if (!preAdapterContext) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001493 hdd_err("SCC: Previous adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001494 continue;
1495 }
1496
1497 /* Previous adapter */
1498 preAdapterContext->
1499 tx_flow_low_watermark = 0;
1500 preAdapterContext->
1501 tx_flow_high_watermark_offset = 0;
1502 cdp_fc_ll_set_tx_pause_q_depth(soc,
1503 preAdapterContext->sessionId,
1504 hdd_ctx->config->
1505 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001506 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001507 hdd_device_mode_to_string(
1508 preAdapterContext->device_mode
1509 ),
1510 preAdapterContext->device_mode,
1511 targetChannel,
1512 preAdapterContext->
1513 tx_flow_low_watermark,
1514 preAdapterContext->
1515 tx_flow_low_watermark +
1516 preAdapterContext->
1517 tx_flow_high_watermark_offset,
1518 hdd_ctx->config->
1519 TxHbwFlowMaxQueueDepth);
1520 }
1521 /*
1522 * MCC, each adapter will have dedicated
1523 * resource
1524 */
1525 else {
1526 /* current channel is 2.4 */
1527 if (targetChannel <=
1528 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1529 channel24 = targetChannel;
1530 channel5 = preAdapterChannel;
1531 adapter2_4 = adapter;
1532 adapter5 = preAdapterContext;
1533 } else {
1534 /* Current channel is 5 */
1535 channel24 = preAdapterChannel;
1536 channel5 = targetChannel;
1537 adapter2_4 = preAdapterContext;
1538 adapter5 = adapter;
1539 }
1540
1541 if (!adapter5) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001542 hdd_err("MCC: 5GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001543 continue;
1544 }
1545 adapter5->tx_flow_low_watermark =
1546 hdd_ctx->config->
1547 TxHbwFlowLowWaterMark;
1548 adapter5->
1549 tx_flow_high_watermark_offset =
1550 hdd_ctx->config->
1551 TxHbwFlowHighWaterMarkOffset;
1552 cdp_fc_ll_set_tx_pause_q_depth(soc,
1553 adapter5->sessionId,
1554 hdd_ctx->config->
1555 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001556 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001557 hdd_device_mode_to_string(
1558 adapter5->device_mode),
1559 adapter5->device_mode,
1560 channel5,
1561 adapter5->tx_flow_low_watermark,
1562 adapter5->
1563 tx_flow_low_watermark +
1564 adapter5->
1565 tx_flow_high_watermark_offset,
1566 hdd_ctx->config->
1567 TxHbwFlowMaxQueueDepth);
1568
1569 if (!adapter2_4) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001570 hdd_err("MCC: 2.4GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001571 continue;
1572 }
1573 adapter2_4->tx_flow_low_watermark =
1574 hdd_ctx->config->
1575 TxLbwFlowLowWaterMark;
1576 adapter2_4->
1577 tx_flow_high_watermark_offset =
1578 hdd_ctx->config->
1579 TxLbwFlowHighWaterMarkOffset;
1580 cdp_fc_ll_set_tx_pause_q_depth(soc,
1581 adapter2_4->sessionId,
1582 hdd_ctx->config->
1583 TxLbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001584 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001585 hdd_device_mode_to_string(
1586 adapter2_4->device_mode),
1587 adapter2_4->device_mode,
1588 channel24,
1589 adapter2_4->
1590 tx_flow_low_watermark,
1591 adapter2_4->
1592 tx_flow_low_watermark +
1593 adapter2_4->
1594 tx_flow_high_watermark_offset,
1595 hdd_ctx->config->
1596 TxLbwFlowMaxQueueDepth);
1597
1598 }
1599 }
1600 }
1601 targetChannel = 0;
1602#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1603 status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext);
1604 adapterNode = pNext;
1605 }
1606 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1607}
1608
1609/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001610 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001612 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1613 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614 *
1615 * Return: true if IPA is enabled, false otherwise
1616 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001617static void __hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001618 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1619{
1620 struct hdd_ipa_priv *hdd_ipa;
1621
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622 *ipa_tx_diff = 0;
1623 *ipa_rx_diff = 0;
1624
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001625 if (wlan_hdd_validate_context(hdd_ctx))
1626 return;
1627
1628 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1629
1630 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1631 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001632 return;
1633 }
1634
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301635 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001636 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1637 (false == hdd_ipa->resource_loading)) {
1638 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1639 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001640 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641 *ipa_tx_diff, *ipa_rx_diff);
1642 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301643 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001644}
1645
1646/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001647 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1648 * @hdd_ctx: Global HDD context
1649 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1650 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1651 *
1652 * Return: true if IPA is enabled, false otherwise
1653 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001654void hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001655 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1656{
1657 cds_ssr_protect(__func__);
1658 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1659 cds_ssr_unprotect(__func__);
1660}
1661
1662/**
1663 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001664 * @adapter: network adapter
1665 * @reason: STAT REQ Reason
1666 *
1667 * Return: None
1668 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07001669static void __hdd_ipa_uc_stat_request(struct hdd_adapter *adapter,
1670 uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001671{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001672 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001673 struct hdd_ipa_priv *hdd_ipa;
1674
Yun Park637d6482016-10-05 10:51:33 -07001675 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001677
Jeff Johnson399c6272017-08-30 10:51:00 -07001678 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001679
1680 if (wlan_hdd_validate_context(hdd_ctx))
1681 return;
1682
1683 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1684 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1685 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686 return;
1687 }
1688
Yun Parkb187d542016-11-14 18:10:04 -08001689 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301690 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1692 (false == hdd_ipa->resource_loading)) {
1693 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07001694 qdf_mutex_release(&hdd_ipa->ipa_lock);
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001695 sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter),
1696 adapter->sessionId,
1697 WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001699 } else {
1700 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702}
1703
1704/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001705 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1706 * @adapter: network adapter
1707 * @reason: STAT REQ Reason
1708 *
1709 * Return: None
1710 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001711void hdd_ipa_uc_stat_request(struct hdd_adapter *adapter, uint8_t reason)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001712{
1713 cds_ssr_protect(__func__);
1714 __hdd_ipa_uc_stat_request(adapter, reason);
1715 cds_ssr_unprotect(__func__);
1716}
1717
Yun Park637d6482016-10-05 10:51:33 -07001718#ifdef FEATURE_METERING
1719/**
1720 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
1721 * @adapter: network adapter
1722 * @reset_stats: reset stat countis after response
1723 *
1724 * Return: None
1725 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001726void hdd_ipa_uc_sharing_stats_request(struct hdd_adapter *adapter,
Yun Park637d6482016-10-05 10:51:33 -07001727 uint8_t reset_stats)
1728{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001729 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001730 struct hdd_ipa_priv *hdd_ipa;
1731
1732 if (!adapter)
1733 return;
1734
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001735 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1736 hdd_ipa = hdd_ctx->hdd_ipa;
1737 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1738 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001739 return;
1740 }
1741
1742 HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats);
1743 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001744 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001745 qdf_mutex_release(&hdd_ipa->ipa_lock);
1746 wma_cli_set_command(
1747 (int)adapter->sessionId,
1748 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
1749 reset_stats, VDEV_CMD);
1750 } else {
1751 qdf_mutex_release(&hdd_ipa->ipa_lock);
1752 }
1753}
1754
1755/**
1756 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
1757 * @adapter: network adapter
1758 * @set_quota: when 1, FW starts quota monitoring
1759 * @quota_bytes: quota limit in bytes
1760 *
1761 * Return: None
1762 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001763void hdd_ipa_uc_set_quota(struct hdd_adapter *adapter, uint8_t set_quota,
Yun Park637d6482016-10-05 10:51:33 -07001764 uint64_t quota_bytes)
1765{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001766 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001767 struct hdd_ipa_priv *hdd_ipa;
1768
1769 if (!adapter)
1770 return;
1771
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001772 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1773 hdd_ipa = hdd_ctx->hdd_ipa;
1774 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1775 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001776 return;
1777 }
1778
1779 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
1780 set_quota, quota_bytes);
1781
1782 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001783 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001784 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park327e7812017-02-14 15:18:10 -08001785 wma_cli_set2_command(
Yun Park637d6482016-10-05 10:51:33 -07001786 (int)adapter->sessionId,
1787 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
Yun Park327e7812017-02-14 15:18:10 -08001788 (set_quota ? quota_bytes&0xffffffff : 0),
1789 (set_quota ? quota_bytes>>32 : 0),
1790 VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001791 } else {
1792 qdf_mutex_release(&hdd_ipa->ipa_lock);
1793 }
1794}
1795#endif
1796
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001797/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1799 * @hdd_ipa: Global HDD IPA context
1800 * @sta_add: Should station be added
1801 * @sta_id: ID of the station being queried
1802 *
1803 * Return: true if the station was found
1804 */
1805static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1806 bool sta_add, uint8_t sta_id)
1807{
1808 bool sta_found = false;
1809 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001810
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001811 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1812 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1813 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1814 sta_found = true;
1815 break;
1816 }
1817 }
1818 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301819 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001820 "STA ID %d already exist, cannot add", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821 return sta_found;
1822 }
1823 if (sta_add) {
1824 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1825 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1826 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1827 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1828 return sta_found;
1829 }
1830 }
1831 }
1832 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301833 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001834 "STA ID %d does not exist, cannot delete", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 return sta_found;
1836 }
1837 if (!sta_add) {
1838 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1839 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1840 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1841 hdd_ipa->assoc_stas_map[idx].is_reserved =
1842 false;
1843 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1844 return sta_found;
1845 }
1846 }
1847 }
1848 return sta_found;
1849}
1850
1851/**
1852 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1853 * @hdd_ipa: Global HDD IPA context
1854 *
1855 * Return: 0 on success, negative errno if error
1856 */
1857static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1858{
Yun Parkfec73dc2017-09-06 10:40:07 -07001859 int result = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07001860 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07001861 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862
Yun Parkfec73dc2017-09-06 10:40:07 -07001863 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
1864
Yun Parkb4f591d2017-03-29 15:51:01 -07001865 result = cdp_ipa_enable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001866 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301867 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001868 "Enable PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001869 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871
Yun Park777d7242017-03-30 15:38:33 -07001872 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Leo Change3e49442015-10-26 20:07:13 -07001873 hdd_ipa->ipa_pipes_down = false;
Yun Parkb4f591d2017-03-29 15:51:01 -07001874
1875 cdp_ipa_enable_autonomy(soc, (struct cdp_pdev *)pdev);
1876
Yun Parkfec73dc2017-09-06 10:40:07 -07001877end:
1878 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: ipa_pipes_down=%d",
1879 hdd_ipa->ipa_pipes_down);
1880 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881}
1882
1883/**
1884 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1885 * @hdd_ipa: Global HDD IPA context
1886 *
1887 * Return: 0 on success, negative errno if error
1888 */
1889static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1890{
Yun Parkb4f591d2017-03-29 15:51:01 -07001891 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1892 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkfec73dc2017-09-06 10:40:07 -07001893 int result = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001894
Yun Parkfec73dc2017-09-06 10:40:07 -07001895 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
Leo Change3e49442015-10-26 20:07:13 -07001896
Yun Parkb4f591d2017-03-29 15:51:01 -07001897 cdp_ipa_disable_autonomy(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001898
Yun Parkb4f591d2017-03-29 15:51:01 -07001899 result = cdp_ipa_disable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301901 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001902 "Disable WDI PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001903 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001904 }
1905
Yun Parkfec73dc2017-09-06 10:40:07 -07001906 hdd_ipa->ipa_pipes_down = true;
1907
1908end:
1909 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: ipa_pipes_down=%d",
1910 hdd_ipa->ipa_pipes_down);
1911 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001912}
1913
1914/**
1915 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1916 * @hdd_ipa: Global HDD IPA context
1917 *
1918 * Return: 0 on success, negative errno if error
1919 */
1920static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1921{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001922 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07001923
Yun Parkfec73dc2017-09-06 10:40:07 -07001924 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
1925
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001926 hdd_ipa->activated_fw_pipe = 0;
1927 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001928
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001929 /* If RM feature enabled
1930 * Request PROD Resource first
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07001931 * PROD resource may return sync or async manners
1932 */
Yun Parkb4f591d2017-03-29 15:51:01 -07001933 if (hdd_ipa_is_rm_enabled(hdd_ctx)) {
Yun Park4cab6ee2015-10-27 11:43:40 -07001934 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1935 /* RM PROD request sync return
1936 * enable pipe immediately
1937 */
Sravan Kumar Kairamc76f28a2017-07-25 19:03:40 +05301938 if (!hdd_ipa->ipa_pipes_down) {
1939 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1940 "%s: IPA WDI Pipe already activated",
1941 __func__);
1942 return 0;
1943 }
1944
Yun Park4cab6ee2015-10-27 11:43:40 -07001945 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301946 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001947 "IPA WDI Pipe activation failed");
Yun Park4cab6ee2015-10-27 11:43:40 -07001948 hdd_ipa->resource_loading = false;
1949 return -EBUSY;
1950 }
Sravan Kumar Kairamc76f28a2017-07-25 19:03:40 +05301951 } else {
1952 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
1953 "%s: IPA WDI Pipe activation deferred",
1954 __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001955 }
1956 } else {
1957 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001958 * Just enabled all the PIPEs
1959 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001960 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301961 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001962 "IPA WDI Pipe activation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001963 hdd_ipa->resource_loading = false;
1964 return -EBUSY;
1965 }
1966 hdd_ipa->resource_loading = false;
1967 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001968
Yun Parkfec73dc2017-09-06 10:40:07 -07001969 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: IPA WDI Pipes activated!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 return 0;
1971}
1972
1973/**
1974 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1975 * @hdd_ipa: Global HDD IPA context
1976 *
1977 * Return: None
1978 */
1979static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1980{
Leo Changfdb45c32016-10-28 11:09:23 -07001981 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07001982 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983
Yun Parkfec73dc2017-09-06 10:40:07 -07001984 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
1985
Yun Parkb4f591d2017-03-29 15:51:01 -07001986 if (!pdev) {
Yun Park7c4f31b2016-11-30 10:09:21 -08001987 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
1988 QDF_ASSERT(0);
1989 return;
1990 }
1991
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001992 hdd_ipa->resource_unloading = true;
Yun Park777d7242017-03-30 15:38:33 -07001993 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Yun Parkb4f591d2017-03-29 15:51:01 -07001994 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW RX PIPE");
1995 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, false);
1996 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW TX PIPE");
1997 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, true);
Yun Parkfec73dc2017-09-06 10:40:07 -07001998
1999 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: IPA WDI Pipes deactivated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002000}
2001
2002/**
2003 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2004 * @context: User context registered with TL (the IPA Global context is
2005 * registered
2006 * @rxpkt: Packet containing the notification
2007 * @staid: ID of the station associated with the packet
2008 *
2009 * Return: None
2010 */
2011static void
2012hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
2013{
2014 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302015 QDF_STATUS status = QDF_STATUS_SUCCESS;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002016 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017
2018 /*
2019 * When SSR is going on or driver is unloading, just return.
2020 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002021 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302022 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002023 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024
Yun Parkb4f591d2017-03-29 15:51:01 -07002025 if (!hdd_ipa_is_rm_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002026 return;
2027
Srinivas Girigowda97852372017-03-06 16:52:59 -08002028 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029 __func__, event);
2030
2031 switch (event) {
2032 case IPA_RM_RESOURCE_GRANTED:
2033 /* Differed RM Granted */
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302034 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002035 if ((false == hdd_ipa->resource_unloading) &&
2036 (!hdd_ipa->activated_fw_pipe)) {
2037 hdd_ipa_uc_enable_pipes(hdd_ipa);
2038 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302039 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002040 break;
2041
2042 case IPA_RM_RESOURCE_RELEASED:
2043 /* Differed RM Released */
2044 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002045 break;
2046
2047 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302048 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002049 "%s, invalid event code %d", __func__, event);
2050 break;
2051 }
2052}
2053
2054/**
2055 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2056 * @hdd_ipa: Global HDD IPA context
2057 * @event: IPA resource manager event to be deferred
2058 *
2059 * This function is called when a resource manager event is received
2060 * from firmware in interrupt context. This function will defer the
2061 * handling to the OL RX thread
2062 *
2063 * Return: None
2064 */
2065static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2066{
2067 enum ipa_rm_event event;
2068 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2069 struct uc_rm_work_struct, work);
2070 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2071 struct hdd_ipa_priv, uc_rm_work);
2072
2073 cds_ssr_protect(__func__);
2074 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002075 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 "%s, posted event %d", __func__, event);
2077
2078 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2079 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002080}
2081
2082/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002083 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
Yun Parkb4f591d2017-03-29 15:51:01 -07002084 * @hdd_ipa: hdd ipa local context
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002085 *
2086 * Will handle IPA UC image loaded indication comes from IPA kernel
2087 *
2088 * Return: None
2089 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002090static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *hdd_ipa)
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002091{
Yun Parkb4f591d2017-03-29 15:51:01 -07002092 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2093 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002094 struct hdd_context *hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07002095 QDF_STATUS status;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002096
2097 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
Yun Parkb4f591d2017-03-29 15:51:01 -07002098 if (true == hdd_ipa->uc_loaded) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002099 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002100 __func__);
2101 return;
2102 }
2103
Yun Parkb4f591d2017-03-29 15:51:01 -07002104 hdd_ctx = hdd_ipa->hdd_ctx;
2105 hdd_ipa->uc_loaded = true;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002106
Yun Parkb4f591d2017-03-29 15:51:01 -07002107 /* Connect pipe */
2108 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
2109 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
2110 hdd_ipa_wdi_meter_notifier_cb,
2111 hdd_ctx->config->IpaDescSize,
2112 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
2113 &hdd_ipa->tx_pipe_handle,
2114 &hdd_ipa->rx_pipe_handle);
2115 if (status) {
2116 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2117 "Failure to setup IPA pipes (status=%d)",
2118 status);
2119 return;
2120 }
2121
2122 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002123
2124 /* If already any STA connected, enable IPA/FW PIPEs */
Yun Parkb4f591d2017-03-29 15:51:01 -07002125 if (hdd_ipa->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002126 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002127 "Client already connected, enable IPA/FW PIPEs");
Yun Parkb4f591d2017-03-29 15:51:01 -07002128 hdd_ipa_uc_handle_first_con(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002129 }
2130}
2131
2132/**
Yun Park637d6482016-10-05 10:51:33 -07002133 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2134 * @hdd_ctx: Global HDD context
2135 * @op_msg: operation message received from firmware
2136 *
2137 * Return: QDF_STATUS enumeration
2138 */
2139#ifdef FEATURE_METERING
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002140static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002141 struct op_msg_type *op_msg)
2142{
2143 struct op_msg_type *msg = op_msg;
2144 struct ipa_uc_sharing_stats *uc_sharing_stats;
2145 struct ipa_uc_quota_rsp *uc_quota_rsp;
2146 struct ipa_uc_quota_ind *uc_quota_ind;
2147 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002148 struct hdd_adapter *adapter;
Yun Park637d6482016-10-05 10:51:33 -07002149
2150 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2151
2152 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2153 /* fill-up ipa_uc_sharing_stats structure from FW */
2154 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2155 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2156
2157 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2158 sizeof(struct ipa_uc_sharing_stats));
2159
2160 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2161
2162 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2163 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2164 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2165 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2166 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2167 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2168 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2169 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2170 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2171 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2172 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2173 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2174 /* received set quota response */
2175 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2176 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2177
2178 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2179 sizeof(struct ipa_uc_quota_rsp));
2180
2181 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2182 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2183 "%s: success=%d, quota_bytes=%llu",
2184 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2185 hdd_ipa->ipa_quota_rsp.success,
2186 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2187 hdd_ipa->ipa_quota_rsp.quota_lo);
2188 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2189 /* hit quota limit */
2190 uc_quota_ind = (struct ipa_uc_quota_ind *)
2191 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2192
2193 hdd_ipa->ipa_quota_ind.quota_bytes =
2194 uc_quota_ind->quota_bytes;
2195
2196 /* send quota exceeded indication to IPA */
2197 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2198 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2199 hdd_ipa->ipa_quota_ind.quota_bytes);
2200
2201 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2202 if (adapter)
2203 ipa_broadcast_wdi_quota_reach_ind(
2204 adapter->dev->ifindex,
2205 uc_quota_ind->quota_bytes);
2206 else
2207 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2208 "Failed quota_reach_ind: NULL adapter");
2209 } else {
2210 return QDF_STATUS_E_INVAL;
2211 }
2212
2213 return QDF_STATUS_SUCCESS;
2214}
2215#else
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002216static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002217 struct op_msg_type *op_msg)
2218{
2219 return QDF_STATUS_E_INVAL;
2220}
2221#endif
2222
2223/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002224 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2225 * @op_msg: operation message received from firmware
2226 * @usr_ctxt: user context registered with TL (we register the HDD Global
2227 * context)
2228 *
2229 * Return: None
2230 */
2231static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2232{
2233 struct op_msg_type *msg = op_msg;
2234 struct ipa_uc_fw_stats *uc_fw_stat;
2235 struct IpaHwStatsWDIInfoData_t ipa_stat;
2236 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002237 struct hdd_context *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302238 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002239
2240 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302241 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002242 return;
2243 }
2244
2245 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302246 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002247 "%s, INVALID OPCODE %d", __func__, msg->op_code);
jiadd91a6842017-08-01 14:46:02 +08002248 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002249 return;
2250 }
2251
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002252 hdd_ctx = (struct hdd_context *) usr_ctxt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002253
2254 /*
2255 * When SSR is going on or driver is unloading, just return.
2256 */
2257 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302258 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302259 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002260 return;
2261 }
2262
2263 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2264
Govind Singhb6a89772016-08-12 11:23:35 +05302265 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002266 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002267
2268 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2269 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302270 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002271 hdd_ipa->activated_fw_pipe++;
2272 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2273 hdd_ipa->resource_loading = false;
Yun Park777d7242017-03-30 15:38:33 -07002274 complete(&hdd_ipa->ipa_resource_comp);
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002275 if (hdd_ipa->wdi_enabled == false) {
2276 hdd_ipa->wdi_enabled = true;
2277 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2278 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2279 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002280 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002281 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002282 if (hdd_ipa->pending_cons_req)
2283 ipa_rm_notify_completion(
2284 IPA_RM_RESOURCE_GRANTED,
2285 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002286 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002287 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302288 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002289 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002290 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302291 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002292 hdd_ipa->activated_fw_pipe--;
2293 if (!hdd_ipa->activated_fw_pipe) {
Yun Park777d7242017-03-30 15:38:33 -07002294 /*
2295 * Async return success from FW
2296 * Disable/suspend all the PIPEs
2297 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002298 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002299 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2300 ipa_rm_release_resource(
2301 IPA_RM_RESOURCE_WLAN_PROD);
Yun Park5b635012015-12-02 15:05:01 -08002302 hdd_ipa->resource_unloading = false;
Yun Park777d7242017-03-30 15:38:33 -07002303 complete(&hdd_ipa->ipa_resource_comp);
Yun Park5b635012015-12-02 15:05:01 -08002304 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2305 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002306 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302307 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002308 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002309 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002310 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302311 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002312 "==== IPA_UC WLAN_HOST RX ====\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002313 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08002314 "NUM TX FWD OK : %llu\n"
2315 "NUM TX FWD ERR : %llu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002316 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08002317 hdd_ipa->stats.num_tx_fwd_ok,
2318 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302319 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002320 "==== IPA_UC WLAN_HOST CONTROL ====\n"
2321 "SAP NUM STAs: %d\n"
2322 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08002323 "CONCURRENT MODE: %s\n"
2324 "TX PIPE HDL: 0x%x\n"
2325 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002326 "RSC LOADING : %d\n"
2327 "RSC UNLOADING : %d\n"
2328 "PNDNG CNS RQT : %d",
2329 hdd_ipa->sap_num_connected_sta,
2330 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08002331 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002332 hdd_ipa->tx_pipe_handle,
2333 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08002334 hdd_ipa->resource_loading,
2335 hdd_ipa->resource_unloading,
2336 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002337
2338 /* STATs from FW */
2339 uc_fw_stat = (struct ipa_uc_fw_stats *)
2340 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302341 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002342 "==== IPA_UC WLAN_FW TX ====\n"
2343 "COMP RING BASE: 0x%x\n"
2344 "COMP RING SIZE: %d\n"
2345 "COMP RING DBELL : 0x%x\n"
2346 "COMP RING DBELL IND VAL : %d\n"
2347 "COMP RING DBELL CACHED VAL : %d\n"
2348 "COMP RING DBELL CACHED VAL : %d\n"
2349 "PKTS ENQ : %d\n"
2350 "PKTS COMP : %d\n"
2351 "IS SUSPEND : %d\n"
2352 "RSVD : 0x%x",
2353 uc_fw_stat->tx_comp_ring_base,
2354 uc_fw_stat->tx_comp_ring_size,
2355 uc_fw_stat->tx_comp_ring_dbell_addr,
2356 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2357 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2358 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2359 uc_fw_stat->tx_pkts_enqueued,
2360 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002361 uc_fw_stat->tx_is_suspend,
2362 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302363 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002364 "==== IPA_UC WLAN_FW RX ====\n"
2365 "IND RING BASE: 0x%x\n"
2366 "IND RING SIZE: %d\n"
2367 "IND RING DBELL : 0x%x\n"
2368 "IND RING DBELL IND VAL : %d\n"
2369 "IND RING DBELL CACHED VAL : %d\n"
2370 "RDY IND ADDR : 0x%x\n"
2371 "RDY IND CACHE VAL : %d\n"
2372 "RFIL IND : %d\n"
2373 "NUM PKT INDICAT : %d\n"
2374 "BUF REFIL : %d\n"
2375 "NUM DROP NO SPC : %d\n"
2376 "NUM DROP NO BUF : %d\n"
2377 "IS SUSPND : %d\n"
2378 "RSVD : 0x%x\n",
2379 uc_fw_stat->rx_ind_ring_base,
2380 uc_fw_stat->rx_ind_ring_size,
2381 uc_fw_stat->rx_ind_ring_dbell_addr,
2382 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2383 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2384 uc_fw_stat->rx_ind_ring_rdidx_addr,
2385 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2386 uc_fw_stat->rx_refill_idx,
2387 uc_fw_stat->rx_num_pkts_indicated,
2388 uc_fw_stat->rx_buf_refilled,
2389 uc_fw_stat->rx_num_ind_drop_no_space,
2390 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002391 uc_fw_stat->rx_is_suspend,
2392 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002393 /* STATs from IPA */
2394 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302395 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002396 "==== IPA_UC IPA TX ====\n"
2397 "NUM PROCD : %d\n"
2398 "CE DBELL : 0x%x\n"
2399 "NUM DBELL FIRED : %d\n"
2400 "COMP RNG FULL : %d\n"
2401 "COMP RNG EMPT : %d\n"
2402 "COMP RNG USE HGH : %d\n"
2403 "COMP RNG USE LOW : %d\n"
2404 "BAM FIFO FULL : %d\n"
2405 "BAM FIFO EMPT : %d\n"
2406 "BAM FIFO USE HGH : %d\n"
2407 "BAM FIFO USE LOW : %d\n"
2408 "NUM DBELL : %d\n"
2409 "NUM UNEXP DBELL : %d\n"
2410 "NUM BAM INT HDL : 0x%x\n"
2411 "NUM BAM INT NON-RUN : 0x%x\n"
2412 "NUM QMB INT HDL : 0x%x",
2413 ipa_stat.tx_ch_stats.num_pkts_processed,
2414 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2415 ipa_stat.tx_ch_stats.num_db_fired,
2416 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2417 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2418 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2419 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2420 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2421 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2422 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2423 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2424 ipa_stat.tx_ch_stats.num_db,
2425 ipa_stat.tx_ch_stats.num_unexpected_db,
2426 ipa_stat.tx_ch_stats.num_bam_int_handled,
2427 ipa_stat.tx_ch_stats.
2428 num_bam_int_in_non_runnning_state,
2429 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2430
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302431 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 "==== IPA_UC IPA RX ====\n"
2433 "MAX OST PKT : %d\n"
2434 "NUM PKT PRCSD : %d\n"
2435 "RNG RP : 0x%x\n"
2436 "COMP RNG FULL : %d\n"
2437 "COMP RNG EMPT : %d\n"
2438 "COMP RNG USE HGH : %d\n"
2439 "COMP RNG USE LOW : %d\n"
2440 "BAM FIFO FULL : %d\n"
2441 "BAM FIFO EMPT : %d\n"
2442 "BAM FIFO USE HGH : %d\n"
2443 "BAM FIFO USE LOW : %d\n"
2444 "NUM DB : %d\n"
2445 "NUM UNEXP DB : %d\n"
2446 "NUM BAM INT HNDL : 0x%x\n",
2447 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2448 ipa_stat.rx_ch_stats.num_pkts_processed,
2449 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2450 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2451 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2452 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2453 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2454 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2455 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2456 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2457 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2458 ipa_stat.rx_ch_stats.num_db,
2459 ipa_stat.rx_ch_stats.num_unexpected_db,
2460 ipa_stat.rx_ch_stats.num_bam_int_handled);
2461 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2462 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2463 /* STATs from FW */
2464 uc_fw_stat = (struct ipa_uc_fw_stats *)
2465 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302466 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002467 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2468 uc_fw_stat->tx_pkts_completed,
2469 hdd_ipa->ipa_p_tx_packets);
2470 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2471 (uc_fw_stat->rx_num_ind_drop_no_space +
2472 uc_fw_stat->rx_num_ind_drop_no_buf +
2473 uc_fw_stat->rx_num_pkts_indicated),
2474 hdd_ipa->ipa_p_rx_packets);
2475
2476 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2477 hdd_ipa->ipa_p_rx_packets =
2478 (uc_fw_stat->rx_num_ind_drop_no_space +
2479 uc_fw_stat->rx_num_ind_drop_no_buf +
2480 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302481 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002482 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2483 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2484 hdd_ipa_uc_loaded_handler(hdd_ipa);
2485 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002486 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2487 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2488 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002489 }
Yun Park8957d802017-01-25 12:27:29 -08002490
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302491 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002492}
2493
2494
2495/**
2496 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2497 * @adapter: device adapter instance
2498 * @offload_type: MCC or SCC
2499 * @enable: TX offload enable or disable
2500 *
2501 * Return: none
2502 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07002503static void hdd_ipa_uc_offload_enable_disable(struct hdd_adapter *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002504 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002505{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002506 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002507 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002508 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002509 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002510
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002511 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002512 return;
2513
Yun Park8292dcb2016-10-07 16:46:06 -07002514 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002515 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002516
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002517 if (!iface_context) {
2518 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2519 "Interface context is NULL");
2520 return;
2521 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08002522 if (session_id >= CSR_ROAM_SESSION_MAX) {
2523 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2524 "invalid session id: %d", session_id);
2525 return;
2526 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002527 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002528 /* IPA offload status is already set as desired */
2529 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002530 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002531 "IPA offload status is already set",
2532 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002533 return;
2534 }
2535
Yun Park4540e862016-11-10 16:30:06 -08002536 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2537 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2538 "invalid session id: %d, offload_type=%d, enable=%d",
2539 adapter->sessionId, offload_type, enable);
2540 return;
2541 }
2542
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302543 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002544 sizeof(ipa_offload_enable_disable));
2545 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002546 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002547 ipa_offload_enable_disable.enable = enable;
2548
Srinivas Girigowda97852372017-03-06 16:52:59 -08002549 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park8292dcb2016-10-07 16:46:06 -07002550 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002551 ipa_offload_enable_disable.offload_type,
2552 ipa_offload_enable_disable.vdev_id,
2553 ipa_offload_enable_disable.enable);
2554
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302555 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002556 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2557 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302558 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002559 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
2560 "Failure to enable IPA offload",
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002561 ipa_offload_enable_disable.offload_type,
2562 ipa_offload_enable_disable.vdev_id,
2563 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002564 } else {
2565 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002566 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002567 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002568 }
2569}
2570
2571/**
2572 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2573 * @work: uC OP work
2574 *
2575 * Return: None
2576 */
2577static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2578{
2579 struct op_msg_type *msg;
2580 struct uc_op_work_struct *uc_op_work = container_of(work,
2581 struct uc_op_work_struct, work);
2582 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2583
2584 cds_ssr_protect(__func__);
2585
2586 msg = uc_op_work->msg;
2587 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002588 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002589 "%s, posted msg %d", __func__, msg->op_code);
2590
2591 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2592
2593 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002594}
2595
2596/**
2597 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2598 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2599 * @op_msg: operation message received from firmware
2600 * @hdd_ctx: Global HDD context
2601 *
2602 * Return: None
2603 */
2604static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2605{
2606 struct hdd_ipa_priv *hdd_ipa;
2607 struct op_msg_type *msg;
2608 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302609 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002610
2611 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302612 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002613 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002614
2615 msg = (struct op_msg_type *)op_msg;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002616 hdd_ipa = ((struct hdd_context *)hdd_ctx)->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002617
2618 if (unlikely(!hdd_ipa))
2619 goto end;
2620
2621 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Yun Parkb4f591d2017-03-29 15:51:01 -07002622 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid OP Code (%d)",
2623 msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002624 goto end;
2625 }
2626
2627 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2628 if (uc_op_work->msg)
2629 /* When the same uC OPCODE is already pended, just return */
2630 goto end;
2631
2632 uc_op_work->msg = msg;
2633 schedule_work(&uc_op_work->work);
2634 return;
2635
2636end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302637 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002638}
2639
2640/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002641 * hdd_ipa_init_uc_op_work - init ipa uc op work
2642 * @work: struct work_struct
2643 * @work_handler: work_handler
2644 *
2645 * Return: none
2646 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002647static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002648 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002649{
2650 INIT_WORK(work, work_handler);
2651}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002652
Yun Park637d6482016-10-05 10:51:33 -07002653#ifdef FEATURE_METERING
2654/**
2655 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2656 * IPA calls to get WLAN stats or set quota limit.
2657 * @priv: pointer to private data registered with IPA (we register a
2658 *» pointer to the global IPA context)
2659 * @evt: the IPA event which triggered the callback
2660 * @data: data associated with the event
2661 *
2662 * Return: None
2663 */
2664static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2665 void *data)
2666{
2667 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002668 struct hdd_adapter *adapter = NULL;
Yun Park637d6482016-10-05 10:51:33 -07002669 struct ipa_get_wdi_sap_stats *wdi_sap_stats;
2670 struct ipa_set_wifi_quota *ipa_set_quota;
2671 int ret = 0;
2672
2673 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2674 return;
2675
2676 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2677
2678 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2679
2680 switch (evt) {
2681 case IPA_GET_WDI_SAP_STATS:
2682 /* fill-up ipa_get_wdi_sap_stats structure after getting
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07002683 * ipa_uc_fw_stats from FW
2684 */
Yun Park637d6482016-10-05 10:51:33 -07002685 wdi_sap_stats = data;
2686
2687 if (!adapter) {
2688 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2689 "IPA uC share stats failed - no adapter");
2690 wdi_sap_stats->stats_valid = 0;
2691 return;
2692 }
2693
2694 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
Yun Park637d6482016-10-05 10:51:33 -07002695 hdd_ipa_uc_sharing_stats_request(adapter,
2696 wdi_sap_stats->reset_stats);
2697 ret = wait_for_completion_timeout(
2698 &hdd_ipa->ipa_uc_sharing_stats_comp,
2699 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2700 if (!ret) {
2701 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2702 "IPA uC share stats request timed out");
2703 wdi_sap_stats->stats_valid = 0;
2704 } else {
2705 wdi_sap_stats->stats_valid = 1;
2706
2707 wdi_sap_stats->ipv4_rx_packets =
2708 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2709 wdi_sap_stats->ipv4_rx_bytes =
2710 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2711 wdi_sap_stats->ipv6_rx_packets =
2712 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2713 wdi_sap_stats->ipv6_rx_bytes =
2714 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
2715 wdi_sap_stats->ipv4_tx_packets =
2716 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
2717 wdi_sap_stats->ipv4_tx_bytes =
2718 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
2719 wdi_sap_stats->ipv6_tx_packets =
2720 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
2721 wdi_sap_stats->ipv6_tx_bytes =
2722 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
2723 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2724 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2725 "IPA_GET_WDI_SAP_STATS",
2726 wdi_sap_stats->stats_valid,
2727 wdi_sap_stats->ipv4_rx_packets,
2728 wdi_sap_stats->ipv4_rx_bytes,
2729 wdi_sap_stats->ipv6_rx_packets,
2730 wdi_sap_stats->ipv6_rx_bytes,
2731 wdi_sap_stats->ipv4_tx_packets,
2732 wdi_sap_stats->ipv4_tx_bytes,
2733 wdi_sap_stats->ipv6_tx_packets,
2734 wdi_sap_stats->ipv6_tx_bytes);
2735 }
2736 break;
2737 case IPA_SET_WIFI_QUOTA:
2738 /* get ipa_set_wifi_quota structure from IPA and pass to FW
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07002739 * through quota_exceeded field in ipa_uc_fw_stats
2740 */
Yun Park637d6482016-10-05 10:51:33 -07002741 ipa_set_quota = data;
2742
2743 if (!adapter) {
2744 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2745 "IPA uC set quota failed - no adapter");
2746 ipa_set_quota->set_valid = 0;
2747 return;
2748 }
2749
Yun Park777d7242017-03-30 15:38:33 -07002750 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
Yun Park637d6482016-10-05 10:51:33 -07002751 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
2752 ipa_set_quota->quota_bytes);
2753
2754 ret = wait_for_completion_timeout(
2755 &hdd_ipa->ipa_uc_set_quota_comp,
2756 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
2757 if (!ret) {
2758 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2759 "IPA uC set quota request timed out");
2760 ipa_set_quota->set_valid = 0;
2761 } else {
2762 ipa_set_quota->quota_bytes =
2763 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
2764 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
2765 ipa_set_quota->set_valid =
2766 hdd_ipa->ipa_quota_rsp.success;
2767 }
2768
2769 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
2770 ipa_set_quota->quota_bytes,
2771 ipa_set_quota->set_valid);
2772 break;
2773 }
2774}
2775
2776/**
2777 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2778 * IPA calls to get WLAN stats or set quota limit.
2779 * @priv: pointer to private data registered with IPA (we register a
Yun Parkb4f591d2017-03-29 15:51:01 -07002780 * pointer to the global IPA context)
Yun Park637d6482016-10-05 10:51:33 -07002781 * @evt: the IPA event which triggered the callback
2782 * @data: data associated with the event
2783 *
2784 * Return: None
2785 */
2786static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt,
2787 void *data)
2788{
2789 cds_ssr_protect(__func__);
2790 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
2791 cds_ssr_unprotect(__func__);
2792}
2793
Yun Parkb4f591d2017-03-29 15:51:01 -07002794static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07002795{
Yun Park637d6482016-10-05 10:51:33 -07002796 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
2797 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
2798}
2799#else
Yun Parkb4f591d2017-03-29 15:51:01 -07002800static void hdd_ipa_wdi_meter_notifier_cb(void)
2801{
2802}
2803
2804static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07002805{
2806}
2807#endif
2808
Rajeev Kumar217f2172016-01-06 18:11:55 -08002809/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002810 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2811 * @hdd_ctx: Global HDD context
2812 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002813 * This function is called to update IPA pipe configuration with resources
2814 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
2815 * (cds_enable)
2816 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302817 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002818 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002819QDF_STATUS hdd_ipa_uc_ol_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002820{
Yun Parkb4f591d2017-03-29 15:51:01 -07002821 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07002822 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002823 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkb4f591d2017-03-29 15:51:01 -07002824 uint8_t i;
2825 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002826
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002827 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2828 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002829
Yun Parkfec73dc2017-09-06 10:40:07 -07002830 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
2831
Manikandan Mohan2e803a02017-02-14 14:57:53 -08002832 /* Do only IPA Pipe specific configuration here. All one time
2833 * initialization wrt IPA UC shall in hdd_ipa_init and those need
2834 * to be reinit at SSR shall in be SSR deinit / reinit functions.
2835 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002836 if (!pdev || !soc) {
2837 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkb4f591d2017-03-29 15:51:01 -07002838 status = QDF_STATUS_E_FAILURE;
Yun Parkbaa62862017-01-18 13:43:34 -08002839 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002840 }
Yun Parkb4f591d2017-03-29 15:51:01 -07002841 if (cdp_ipa_get_resource(soc, (struct cdp_pdev *)pdev)) {
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002842 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2843 "IPA UC resource alloc fail");
2844 return QDF_STATUS_E_FAILURE;
2845 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002846
Yun Parkb4f591d2017-03-29 15:51:01 -07002847 if (true == hdd_ipa->uc_loaded) {
2848 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
2849 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
2850 hdd_ipa_wdi_meter_notifier_cb,
2851 hdd_ctx->config->IpaDescSize,
2852 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
2853 &hdd_ipa->tx_pipe_handle,
2854 &hdd_ipa->rx_pipe_handle);
2855 if (status) {
Yun Parkbaa62862017-01-18 13:43:34 -08002856 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002857 "Failure to setup IPA pipes (status=%d)",
2858 status);
2859 return QDF_STATUS_E_FAILURE;
Yun Parkbaa62862017-01-18 13:43:34 -08002860 }
Yun Park637d6482016-10-05 10:51:33 -07002861
Yun Parkb4f591d2017-03-29 15:51:01 -07002862 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
2863 hdd_ipa_init_metering(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002864 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002865
Yun Parkb4f591d2017-03-29 15:51:01 -07002866 cdp_ipa_register_op_cb(soc, (struct cdp_pdev *)pdev,
Yun Parkbaa62862017-01-18 13:43:34 -08002867 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
2868
Yun Parkb4f591d2017-03-29 15:51:01 -07002869 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
2870 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
2871 hdd_ipa_uc_fw_op_event_handler);
2872 hdd_ipa->uc_op_work[i].msg = NULL;
2873 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002874
Yun Parkbaa62862017-01-18 13:43:34 -08002875fail_return:
Yun Parkfec73dc2017-09-06 10:40:07 -07002876 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: stat=%d", stat);
Yun Parkb4f591d2017-03-29 15:51:01 -07002877 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002878}
2879
Leo Change3e49442015-10-26 20:07:13 -07002880/**
Yun Parkd8fb1a82017-10-13 16:48:20 -07002881 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
2882 * @hdd_ipa: pointer to HDD IPA struct
2883 *
2884 * Return: none
2885 */
2886static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
2887{
2888 struct ipa_uc_pending_event *pending_event = NULL;
2889
2890 while (qdf_list_remove_front(&hdd_ipa->pending_event,
2891 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
2892 qdf_mem_free(pending_event);
2893}
2894
2895/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302896 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
2897 * @hdd_ctx: Global HDD context
2898 *
2899 * Return: 0 on success, negativer errno on error
2900 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002901int hdd_ipa_uc_ol_deinit(struct hdd_context *hdd_ctx)
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302902{
2903 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
2904 int ret = 0;
Yun Parkb4f591d2017-03-29 15:51:01 -07002905 QDF_STATUS status;
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302906
Yun Parkfec73dc2017-09-06 10:40:07 -07002907 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
2908
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302909 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2910 return ret;
2911
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05302912 if (!hdd_ipa->ipa_pipes_down)
2913 hdd_ipa_uc_disable_pipes(hdd_ipa);
2914
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302915 if (true == hdd_ipa->uc_loaded) {
Yun Parkb4f591d2017-03-29 15:51:01 -07002916 status = cdp_ipa_cleanup(cds_get_context(QDF_MODULE_ID_SOC),
2917 hdd_ipa->tx_pipe_handle,
2918 hdd_ipa->rx_pipe_handle);
2919 if (status) {
2920 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2921 "Failure to cleanup IPA pipes (status=%d)",
2922 status);
2923 return -EFAULT;
2924 }
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302925 }
2926
Yun Parkd8fb1a82017-10-13 16:48:20 -07002927 hdd_ipa_cleanup_pending_event(hdd_ipa);
2928
Yun Parkfec73dc2017-09-06 10:40:07 -07002929 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: ret=%d", ret);
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05302930 return ret;
2931}
2932
2933/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002934 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002935 * @hdd_ctx: hdd main context
2936 *
2937 * Force shutdown IPA pipe
2938 * Independent of FW pipe status, IPA pipe shutdonw progress
2939 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2940 * independent from FW pipe status
2941 *
2942 * Return: NONE
2943 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002944static void __hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002945{
2946 struct hdd_ipa_priv *hdd_ipa;
2947
Yun Parkfec73dc2017-09-06 10:40:07 -07002948 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
2949
Leo Change3e49442015-10-26 20:07:13 -07002950 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2951 return;
2952
2953 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2954 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302955 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002956 "IPA pipes are not down yet, force shutdown");
Leo Change3e49442015-10-26 20:07:13 -07002957 hdd_ipa_uc_disable_pipes(hdd_ipa);
2958 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002959 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb4f591d2017-03-29 15:51:01 -07002960 "IPA pipes are down, do nothing");
Leo Change3e49442015-10-26 20:07:13 -07002961 }
Yun Parkfec73dc2017-09-06 10:40:07 -07002962
2963 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit");
Leo Change3e49442015-10-26 20:07:13 -07002964}
2965
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002966/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002967 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2968 * __hdd_ipa_uc_force_pipe_shutdown
2969 * @hdd_ctx: hdd main context
2970 *
2971 * Force shutdown IPA pipe
2972 * Independent of FW pipe status, IPA pipe shutdonw progress
2973 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2974 * independent from FW pipe status
2975 *
2976 * Return: NONE
2977 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002978void hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002979{
2980 cds_ssr_protect(__func__);
2981 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2982 cds_ssr_unprotect(__func__);
2983}
2984
2985/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302986 * hdd_ipa_msg_free_fn() - Free an IPA message
2987 * @buff: pointer to the IPA message
2988 * @len: length of the IPA message
2989 * @type: type of IPA message
2990 *
2991 * Return: None
2992 */
2993static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2994{
Srinivas Girigowda97852372017-03-06 16:52:59 -08002995 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05302996 ghdd_ipa->stats.num_free_msg++;
2997 qdf_mem_free(buff);
2998}
2999
Govind Singh9c58eba2016-09-02 16:23:06 +05303000/**
jge62037862016-12-09 10:44:33 +08003001 * hdd_ipa_uc_send_evt() - send event to ipa
3002 * @hdd_ctx: pointer to hdd context
3003 * @type: event type
3004 * @mac_addr: pointer to mac address
3005 *
3006 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303007 *
3008 * Return: 0 - Success
3009 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003010static int hdd_ipa_uc_send_evt(struct hdd_adapter *adapter,
jge62037862016-12-09 10:44:33 +08003011 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303012{
jge62037862016-12-09 10:44:33 +08003013 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05303014 struct ipa_msg_meta meta;
3015 struct ipa_wlan_msg *msg;
3016 int ret = 0;
jge62037862016-12-09 10:44:33 +08003017
3018 meta.msg_len = sizeof(struct ipa_wlan_msg);
3019 msg = qdf_mem_malloc(meta.msg_len);
3020 if (msg == NULL) {
3021 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3022 "msg allocation failed");
3023 return -ENOMEM;
3024 }
3025
3026 meta.msg_type = type;
3027 strlcpy(msg->name, adapter->dev->name,
3028 IPA_RESOURCE_NAME_MAX);
3029 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
Yun Parkfec73dc2017-09-06 10:40:07 -07003030 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "%s: Evt: %d",
jge62037862016-12-09 10:44:33 +08003031 msg->name, meta.msg_type);
3032 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
3033 if (ret) {
3034 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3035 "%s: Evt: %d fail:%d",
3036 msg->name, meta.msg_type, ret);
3037 qdf_mem_free(msg);
3038 return ret;
3039 }
3040
3041 hdd_ipa->stats.num_send_msg++;
3042
3043 return ret;
3044}
3045
3046/**
3047 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3048 * @hdd_ctx: pointer to hdd adapter
3049 *
3050 * Send disconnect client event to IPA driver during SSR
3051 *
3052 * Return: 0 - Success
3053 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003054static int hdd_ipa_uc_disconnect_client(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003055{
3056 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3057 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303058 int i;
3059
Yun Parkfec73dc2017-09-06 10:40:07 -07003060 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
Govind Singh9c58eba2016-09-02 16:23:06 +05303061 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
3062 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
3063 continue;
3064 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08003065 (!adapter->aStaInfo[i].isDeauthInProgress) &&
3066 hdd_ipa->sap_num_connected_sta) {
3067 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
3068 adapter->aStaInfo[i].macAddrSTA.bytes);
3069 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303070 }
3071 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003072 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: sap_num_connected_sta=%d",
3073 hdd_ipa->sap_num_connected_sta);
Govind Singh9c58eba2016-09-02 16:23:06 +05303074
3075 return ret;
3076}
3077
3078/**
jge62037862016-12-09 10:44:33 +08003079 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3080 * @hdd_ctx: pointer to hdd adapter
3081 *
3082 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303083 *
3084 * Return: 0 - Success
3085 */
jge62037862016-12-09 10:44:33 +08003086
Jeff Johnson49d45e62017-08-29 14:30:42 -07003087static int hdd_ipa_uc_disconnect_ap(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003088{
3089 int ret = 0;
3090
Yun Parkfec73dc2017-09-06 10:40:07 -07003091 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
3092 if (adapter->ipa_context) {
jge62037862016-12-09 10:44:33 +08003093 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3094 adapter->dev->dev_addr);
Yun Parkfec73dc2017-09-06 10:40:07 -07003095 }
3096 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit");
jge62037862016-12-09 10:44:33 +08003097
3098 return ret;
3099}
3100
jge62037862016-12-09 10:44:33 +08003101/**
3102 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3103 * @hdd_ctx: pointer to hdd adapter
3104 *
3105 * Send disconnect sta event to IPA driver during SSR
3106 *
3107 * Return: 0 - Success
3108 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003109static int hdd_ipa_uc_disconnect_sta(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003110{
Jeff Johnsond377dce2017-10-04 10:32:42 -07003111 struct hdd_station_ctx *sta_ctx;
jge62037862016-12-09 10:44:33 +08003112 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3113 int ret = 0;
3114
Yun Parkfec73dc2017-09-06 10:40:07 -07003115 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003116 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003117 hdd_ipa->sta_connected) {
Jeff Johnsond377dce2017-10-04 10:32:42 -07003118 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
jge62037862016-12-09 10:44:33 +08003119 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Jeff Johnsond377dce2017-10-04 10:32:42 -07003120 sta_ctx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003121 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003122 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit");
jge62037862016-12-09 10:44:33 +08003123
3124 return ret;
3125}
jge62037862016-12-09 10:44:33 +08003126
3127/**
3128 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3129 * @hdd_ctx: pointer to hdd context
3130 *
3131 * Send disconnect event to IPA driver during SSR
3132 *
3133 * Return: 0 - Success
3134 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003135static int hdd_ipa_uc_disconnect(struct hdd_context *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303136{
3137 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
3138 QDF_STATUS status;
Jeff Johnson49d45e62017-08-29 14:30:42 -07003139 struct hdd_adapter *adapter;
Govind Singh9c58eba2016-09-02 16:23:06 +05303140 int ret = 0;
3141
Govind Singh9c58eba2016-09-02 16:23:06 +05303142 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
3143 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Jeff Johnson57eb2732017-10-02 11:40:20 -07003144 adapter = adapter_node->adapter;
jge62037862016-12-09 10:44:33 +08003145 if (adapter->device_mode == QDF_SAP_MODE) {
3146 hdd_ipa_uc_disconnect_client(adapter);
3147 hdd_ipa_uc_disconnect_ap(adapter);
3148 } else if (adapter->device_mode == QDF_STA_MODE) {
3149 hdd_ipa_uc_disconnect_sta(adapter);
3150 }
3151
Govind Singh9c58eba2016-09-02 16:23:06 +05303152 status = hdd_get_next_adapter(
3153 hdd_ctx, adapter_node, &next);
3154 adapter_node = next;
3155 }
3156
3157 return ret;
3158}
3159
3160/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003161 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003162 *
3163 * Deinit basic IPA UC host side to be in sync reloaded FW during
3164 * SSR
3165 *
3166 * Return: 0 - Success
3167 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003168static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003169{
3170 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3171 int idx;
3172 struct hdd_ipa_iface_context *iface_context;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003173 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003174
Yun Parkfec73dc2017-09-06 10:40:07 -07003175 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
3176
Arun Khandavallicc544b32017-01-30 19:52:16 +05303177 if (!hdd_ipa)
3178 return 0;
3179
3180 hdd_ctx = hdd_ipa->hdd_ctx;
3181 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003182 return 0;
3183
jge62037862016-12-09 10:44:33 +08003184 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303185 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003186
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003187 /* Clean up HDD IPA interfaces */
3188 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3189 (idx < HDD_IPA_MAX_IFACE); idx++) {
3190 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003191 if (iface_context->adapter && iface_context->adapter->magic ==
3192 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003193 hdd_ipa_cleanup_iface(iface_context);
3194 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003195 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003196 /* After SSR, wlan driver reloads FW again. But we need to protect
3197 * IPA submodule during SSR transient state. So deinit basic IPA
3198 * UC host side to be in sync with reloaded FW during SSR
3199 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003200
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303201 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003202 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3203 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3204 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3205 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303206 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003207
Guolei Bianca144d82016-11-10 11:07:42 +08003208 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3209 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3210
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003211 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
3212 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
3213 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
3214 hdd_ipa->uc_op_work[idx].msg = NULL;
3215 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003216
3217 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003218 return 0;
3219}
3220
3221/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003222 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3223 *
3224 * Deinit basic IPA UC host side to be in sync reloaded FW during
3225 * SSR
3226 *
3227 * Return: 0 - Success
3228 */
3229int hdd_ipa_uc_ssr_deinit(void)
3230{
3231 int ret;
3232
3233 cds_ssr_protect(__func__);
3234 ret = __hdd_ipa_uc_ssr_deinit();
3235 cds_ssr_unprotect(__func__);
3236
3237 return ret;
3238}
3239
3240/**
3241 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003242 *
3243 * Init basic IPA UC host side to be in sync with reloaded FW after
3244 * SSR to resume IPA UC operations
3245 *
3246 * Return: 0 - Success
3247 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003248static int __hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003249{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003250
Arun Khandavallicc544b32017-01-30 19:52:16 +05303251 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3252 int i;
3253 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303254
Yun Parkfec73dc2017-09-06 10:40:07 -07003255 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
3256
Arun Khandavallicc544b32017-01-30 19:52:16 +05303257 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3258 return 0;
3259
Arun Khandavallicc544b32017-01-30 19:52:16 +05303260 /* Create the interface context */
3261 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3262 iface_context = &hdd_ipa->iface_context[i];
3263 iface_context->hdd_ipa = hdd_ipa;
3264 iface_context->cons_client =
3265 hdd_ipa_adapter_2_client[i].cons_client;
3266 iface_context->prod_client =
3267 hdd_ipa_adapter_2_client[i].prod_client;
3268 iface_context->iface_id = i;
3269 iface_context->adapter = NULL;
3270 }
3271 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3272 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3273 hdd_ipa->vdev_offload_enabled[i] = false;
3274 }
3275
3276 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3277 hdd_ipa->resource_loading = false;
3278 hdd_ipa->resource_unloading = false;
3279 hdd_ipa->sta_connected = 0;
3280 hdd_ipa->ipa_pipes_down = true;
3281 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303282 }
3283
Yun Parkfec73dc2017-09-06 10:40:07 -07003284 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003285 return 0;
3286}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003287
3288/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003289 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3290 *
3291 * Init basic IPA UC host side to be in sync with reloaded FW after
3292 * SSR to resume IPA UC operations
3293 *
3294 * Return: 0 - Success
3295 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003296int hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003297{
3298 int ret;
3299
3300 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303301 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003302 cds_ssr_unprotect(__func__);
3303
3304 return ret;
3305}
3306
3307/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003308 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3309 * @work: scheduled work
3310 *
3311 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3312 * not want to immediately release the wake lock since the system
3313 * would then potentially try to suspend when there is a healthy data
3314 * rate. Deferred work is scheduled and this function handles the
3315 * work. When this function is called, if the IPA resource is still
3316 * released then we release the wake lock.
3317 *
3318 * Return: None
3319 */
3320static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3321{
3322 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3323 struct hdd_ipa_priv,
3324 wake_lock_work);
3325
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303326 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003327
3328 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3329 goto end;
3330
3331 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303332 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003333 WIFI_POWER_EVENT_WAKELOCK_IPA);
3334
3335end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303336 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003337}
3338
3339/**
3340 * hdd_ipa_rm_request() - Request resource from IPA
3341 * @hdd_ipa: Global HDD IPA context
3342 *
3343 * Return: 0 on success, negative errno on error
3344 */
3345static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3346{
3347 int ret = 0;
3348
3349 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3350 return 0;
3351
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303352 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003353
3354 switch (hdd_ipa->rm_state) {
3355 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303356 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003357 return 0;
3358 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303359 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003360 return -EINPROGRESS;
3361 case HDD_IPA_RM_RELEASED:
3362 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3363 break;
3364 }
3365
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303366 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003367
3368 ret = ipa_rm_inactivity_timer_request_resource(
3369 IPA_RM_RESOURCE_WLAN_PROD);
3370
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303371 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003372 if (ret == 0) {
3373 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3374 hdd_ipa->stats.num_rm_grant_imm++;
3375 }
3376
3377 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3378 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303379 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003380 WIFI_POWER_EVENT_WAKELOCK_IPA);
3381 hdd_ipa->wake_lock_released = false;
3382 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303383 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003384
3385 return ret;
3386}
3387
3388/**
3389 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3390 * @hdd_ipa: Global HDD IPA context
3391 *
3392 * Return: 0 if resources released, negative errno otherwise
3393 */
3394static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3395{
3396 int ret = 0;
3397
3398 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3399 return 0;
3400
3401 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3402 return -EAGAIN;
3403
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303404 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003405
Nirav Shahcbc6d722016-03-01 16:24:53 +05303406 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303407 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003408 return -EAGAIN;
3409 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303410 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003411
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303412 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413 switch (hdd_ipa->rm_state) {
3414 case HDD_IPA_RM_GRANTED:
3415 break;
3416 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303417 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418 return -EINPROGRESS;
3419 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303420 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421 return 0;
3422 }
3423
3424 /* IPA driver returns immediately so set the state here to avoid any
3425 * race condition.
3426 */
3427 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3428 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303429 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003430
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003431 ret = ipa_rm_inactivity_timer_release_resource(
3432 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303434 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003435 if (unlikely(ret != 0)) {
3436 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3437 WARN_ON(1);
3438 }
3439
3440 /*
3441 * If wake_lock is released immediately, kernel would try to suspend
3442 * immediately as well, Just avoid ping-pong between suspend-resume
3443 * while there is healthy amount of data transfer going on by
3444 * releasing the wake_lock after some delay.
3445 */
3446 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3447 msecs_to_jiffies
3448 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3449
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303450 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003451
3452 return ret;
3453}
3454
3455/**
3456 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3457 * @user_data: user data registered with IPA
3458 * @event: the IPA resource manager event that occurred
3459 * @data: the data associated with the event
3460 *
3461 * Return: None
3462 */
3463static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3464 unsigned long data)
3465{
3466 struct hdd_ipa_priv *hdd_ipa = user_data;
3467
3468 if (unlikely(!hdd_ipa))
3469 return;
3470
3471 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3472 return;
3473
Srinivas Girigowda97852372017-03-06 16:52:59 -08003474 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003475
3476 switch (event) {
3477 case IPA_RM_RESOURCE_GRANTED:
3478 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3479 /* RM Notification comes with ISR context
3480 * it should be serialized into work queue to avoid
3481 * ISR sleep problem
3482 */
3483 hdd_ipa->uc_rm_work.event = event;
3484 schedule_work(&hdd_ipa->uc_rm_work.work);
3485 break;
3486 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303487 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003488 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303489 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003490 hdd_ipa->stats.num_rm_grant++;
3491 break;
3492
3493 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003494 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003495 hdd_ipa->resource_unloading = false;
3496 break;
3497
3498 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303499 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003500 break;
3501 }
3502}
3503
3504/**
3505 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3506 *
3507 * Callback function registered with IPA that is called when IPA wants
3508 * to release the WLAN consumer resource
3509 *
3510 * Return: 0 if the request is granted, negative errno otherwise
3511 */
3512static int hdd_ipa_rm_cons_release(void)
3513{
3514 return 0;
3515}
3516
3517/**
3518 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3519 *
3520 * Callback function registered with IPA that is called when IPA wants
3521 * to access the WLAN consumer resource
3522 *
3523 * Return: 0 if the request is granted, negative errno otherwise
3524 */
3525static int hdd_ipa_rm_cons_request(void)
3526{
Yun Park4d8b60a2015-10-22 13:59:32 -07003527 int ret = 0;
3528
3529 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303530 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003531 "IPA resource loading in progress");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003532 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003533 ret = -EINPROGRESS;
3534 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303535 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003536 "IPA resource unloading in progress");
Yun Park4d8b60a2015-10-22 13:59:32 -07003537 ghdd_ipa->pending_cons_req = true;
3538 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003539 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003540
3541 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003542}
3543
3544/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003545 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003546 * @hdd_ctx: Global HDD context
3547 * @tx_packets: Number of packets transmitted in the last sample period
3548 * @rx_packets: Number of packets received in the last sample period
3549 *
3550 * Return: 0 on success, negative errno on error
3551 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07003552static int __hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx,
3553 uint64_t tx_packets,
3554 uint64_t rx_packets)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003555{
3556 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003557 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003558 struct ipa_rm_perf_profile profile;
Yun Parkb4f591d2017-03-29 15:51:01 -07003559 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003560 int ret;
3561
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003562 if (wlan_hdd_validate_context(hdd_ctx))
3563 return 0;
3564
3565 hdd_ipa = hdd_ctx->hdd_ipa;
3566
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003567 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3568 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3569 return 0;
3570
3571 memset(&profile, 0, sizeof(profile));
3572
3573 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3574 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3575 else if (tx_packets >
3576 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3577 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3578 else
3579 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3580
3581 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3582 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3583 else if (rx_packets >
3584 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3585 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3586 else
3587 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3588
Yun Parkec845302016-12-15 09:22:57 -08003589 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590 "CONS perf curr: %d, next: %d",
3591 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003592 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003593 "PROD perf curr: %d, next: %d",
3594 hdd_ipa->curr_prod_bw, next_prod_bw);
3595
3596 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003597 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003598 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003599 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS,
3600 next_cons_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003601 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003602 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003603
3604 return ret;
3605 }
3606 hdd_ipa->curr_cons_bw = next_cons_bw;
3607 hdd_ipa->stats.num_cons_perf_req++;
3608 }
3609
3610 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003611 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003612 hdd_ipa->curr_prod_bw, next_prod_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003613 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD,
3614 next_prod_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003615 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003616 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003617 return ret;
3618 }
3619 hdd_ipa->curr_prod_bw = next_prod_bw;
3620 hdd_ipa->stats.num_prod_perf_req++;
3621 }
3622
3623 return 0;
3624}
3625
3626/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003627 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3628 * @hdd_ctx: Global HDD context
3629 * @tx_packets: Number of packets transmitted in the last sample period
3630 * @rx_packets: Number of packets received in the last sample period
3631 *
3632 * Return: 0 on success, negative errno on error
3633 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003634int hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003635 uint64_t rx_packets)
3636{
3637 int ret;
3638
3639 cds_ssr_protect(__func__);
3640 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3641 cds_ssr_unprotect(__func__);
3642
3643 return ret;
3644}
3645
3646/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003647 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3648 * @work: struct work_struct
3649 * @work_handler: work_handler
3650 *
3651 * Return: none
3652 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003653static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3654 work_func_t work_handler)
3655{
3656 INIT_WORK(work, work_handler);
3657}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003658
3659/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003660 * hdd_ipa_setup_rm() - Setup IPA resource management
3661 * @hdd_ipa: Global HDD IPA context
3662 *
3663 * Return: 0 on success, negative errno on error
3664 */
3665static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3666{
3667 struct ipa_rm_create_params create_params = { 0 };
3668 int ret;
3669
3670 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3671 return 0;
3672
Rajeev Kumar217f2172016-01-06 18:11:55 -08003673 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3674 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003675 memset(&create_params, 0, sizeof(create_params));
3676 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3677 create_params.reg_params.user_data = hdd_ipa;
3678 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3679 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3680
3681 ret = ipa_rm_create_resource(&create_params);
3682 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303683 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684 "Create RM resource failed: %d", ret);
3685 goto setup_rm_fail;
3686 }
3687
3688 memset(&create_params, 0, sizeof(create_params));
3689 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3690 create_params.request_resource = hdd_ipa_rm_cons_request;
3691 create_params.release_resource = hdd_ipa_rm_cons_release;
3692 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3693
3694 ret = ipa_rm_create_resource(&create_params);
3695 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303696 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003697 "Create RM CONS resource failed: %d", ret);
3698 goto delete_prod;
3699 }
3700
3701 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3702 IPA_RM_RESOURCE_APPS_CONS);
3703
3704 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3705 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3706 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303707 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708 ret);
3709 goto timer_init_failed;
3710 }
3711
3712 /* Set the lowest bandwidth to start with */
3713 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3714
3715 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303716 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003717 "Set perf level failed: %d", ret);
3718 goto set_perf_failed;
3719 }
3720
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303721 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003722 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3723 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303724 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003725 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3726 hdd_ipa->wake_lock_released = true;
3727 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3728
3729 return ret;
3730
3731set_perf_failed:
3732 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3733
3734timer_init_failed:
3735 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3736
3737delete_prod:
3738 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3739
3740setup_rm_fail:
3741 return ret;
3742}
3743
3744/**
3745 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3746 * @hdd_ipa: Global HDD IPA context
3747 *
3748 * Destroys all resources associated with the IPA resource manager
3749 *
3750 * Return: None
3751 */
3752static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3753{
3754 int ret;
3755
3756 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3757 return;
3758
3759 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303760 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003761
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003762 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303763 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003764
3765 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3766
3767 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3768 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303769 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003770 "RM PROD resource delete failed %d", ret);
3771
3772 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3773 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303774 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003775 "RM CONS resource delete failed %d", ret);
3776}
3777
tfyu0380a972017-07-13 18:19:37 +08003778#ifdef QCA_CONFIG_SMP
3779static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
3780{
3781 return netif_rx_ni(skb);
3782}
3783#else
3784static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
3785{
3786 struct iphdr *ip_h;
3787 static atomic_t softirq_mitigation_cntr =
3788 ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH);
3789 int result;
3790
3791 ip_h = (struct iphdr *)(skb->data);
3792 if ((skb->protocol == htons(ETH_P_IP)) &&
3793 (ip_h->protocol == IPPROTO_ICMP)) {
3794 result = netif_rx_ni(skb);
3795 } else {
3796 /* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets
3797 * to avoid excessive softirq's.
3798 */
3799 if (atomic_dec_and_test(&softirq_mitigation_cntr)) {
3800 result = netif_rx_ni(skb);
3801 atomic_set(&softirq_mitigation_cntr,
3802 IPA_WLAN_RX_SOFTIRQ_THRESH);
3803 } else {
3804 result = netif_rx(skb);
3805 }
3806 }
3807
3808 return result;
3809}
3810#endif
3811
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003812/**
3813 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3814 * @skb: network buffer
3815 * @adapter: network adapter
3816 *
3817 * Called when a network buffer is received which should not be routed
3818 * to the IPA module.
3819 *
3820 * Return: None
3821 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303822static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Jeff Johnson49d45e62017-08-29 14:30:42 -07003823 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003824{
tfyu0380a972017-07-13 18:19:37 +08003825 int result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3827 unsigned int cpu_index;
3828
3829 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Jeff Johnson36e74c42017-09-18 08:15:42 -07003830 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%pK",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003831 adapter);
3832 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003833 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003834 return;
3835 }
3836
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003837 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003838 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003839 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003840 return;
3841 }
3842
3843 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3844 skb->dev = adapter->dev;
3845 skb->protocol = eth_type_trans(skb, skb->dev);
3846 skb->ip_summed = CHECKSUM_NONE;
3847
3848 cpu_index = wlan_hdd_get_cpu();
3849
3850 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
tfyu0380a972017-07-13 18:19:37 +08003851 result = hdd_ipa_aggregated_rx_ind(skb);
3852 if (result == NET_RX_SUCCESS)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003853 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3854 else
3855 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3856
3857 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858}
3859
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003860/**
Leo Chang69c39692016-10-12 20:11:12 -07003861 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3862 * @hdd_ipa: pointer to hdd ipa context
3863 * @adapter: network adapter
3864 * @skb: data pointer
3865 *
3866 * if exception packet has set forward bit, copied new packet should be
3867 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3868 * put into pm queue and tx procedure will be differed
3869 *
3870 * Return: None
3871 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003872static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07003873 struct hdd_adapter *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003874{
Leo Chang69c39692016-10-12 20:11:12 -07003875 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3876
Leo Chang69c39692016-10-12 20:11:12 -07003877 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Yun Park01deb2c2017-06-14 15:21:44 -07003878
3879 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
3880 qdf_nbuf_ipa_owned_set(skb);
3881
Leo Chang69c39692016-10-12 20:11:12 -07003882 /* WLAN subsystem is in suspend, put int queue */
3883 if (hdd_ipa->suspended) {
3884 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3885 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3886 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003887 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3888 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003889 pm_tx_cb->exception = true;
3890 pm_tx_cb->adapter = adapter;
3891 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003892 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003893 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3894 hdd_ipa->stats.num_tx_queued++;
3895 } else {
3896 /* Resume, put packet into WLAN TX */
3897 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003898 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003899 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3900 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003901 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003902 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003903 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003904 hdd_ipa->ipa_tx_forward++;
3905 }
3906 }
3907}
3908
3909/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003910 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3911 * @hdd_ipa: pointer to HDD IPA struct
3912 * @adapter: hdd adapter pointer
3913 * @desc: Firmware descriptor
3914 * @skb: Data buffer
3915 *
3916 * Return:
3917 * HDD_IPA_FORWARD_PKT_NONE
3918 * HDD_IPA_FORWARD_PKT_DISCARD
3919 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3920 *
3921 */
3922
3923static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3924 struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07003925 struct hdd_adapter *adapter,
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003926 uint8_t desc,
3927 qdf_nbuf_t skb)
3928{
3929 int ret = HDD_IPA_FORWARD_PKT_NONE;
3930
3931 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303932 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003933 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
3934 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303935 /* Drop the packet*/
3936 hdd_ipa->stats.num_tx_fwd_err++;
3937 kfree_skb(skb);
3938 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3939 return ret;
3940 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003941 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3942 "Forward packet to Tx (fw_desc=%d)", desc);
3943 hdd_ipa->ipa_tx_forward++;
3944
3945 if ((desc & FW_RX_DESC_DISCARD_M)) {
3946 hdd_ipa_forward(hdd_ipa, adapter, skb);
3947 hdd_ipa->ipa_rx_internel_drop_count++;
3948 hdd_ipa->ipa_rx_discard++;
3949 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3950 } else {
3951 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003952
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003953 if (cloned_skb)
3954 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3955 else
3956 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3957 "%s: tx skb alloc failed",
3958 __func__);
3959 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3960 }
3961 }
3962
3963 return ret;
3964}
3965
3966/**
Yun Park637d6482016-10-05 10:51:33 -07003967 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003968 * @priv: pointer to private data registered with IPA (we register a
3969 * pointer to the global IPA context)
3970 * @evt: the IPA event which triggered the callback
3971 * @data: data associated with the event
3972 *
3973 * Return: None
3974 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003975static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003976 unsigned long data)
3977{
3978 struct hdd_ipa_priv *hdd_ipa = NULL;
Jeff Johnson49d45e62017-08-29 14:30:42 -07003979 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303980 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003981 uint8_t iface_id;
3982 uint8_t session_id;
3983 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003984 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003985 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003986
3987 hdd_ipa = (struct hdd_ipa_priv *)priv;
3988
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003989 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3990 return;
3991
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003992 switch (evt) {
3993 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303994 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003995
3996 /*
3997 * When SSR is going on or driver is unloading,
3998 * just drop the packets.
3999 */
4000 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4001 if (0 != status) {
4002 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4003 "Invalid context: drop packet");
4004 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4005 kfree_skb(skb);
4006 return;
4007 }
4008
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004009 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4010 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004011 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004012 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004013 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4014 session_id, iface_id);
4015 } else {
4016 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4017 }
4018
4019 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304020 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004021 "IPA_RECEIVE: Invalid iface_id: %u",
4022 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004023 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004024 "w2i -- skb",
4025 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004026 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07004027 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028 return;
4029 }
4030
4031 iface_context = &hdd_ipa->iface_context[iface_id];
4032 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08004033 if (!adapter) {
4034 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4035 "IPA_RECEIVE: Adapter is NULL");
4036 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
4037 kfree_skb(skb);
4038 return;
4039 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004040
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304041 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004042 "w2i -- skb",
4043 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004044 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4045 hdd_ipa->stats.num_rx_excep++;
4046 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4047 } else {
4048 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4049 }
4050
4051 iface_context->stats.num_rx_ipa_excep++;
4052
4053 /* Disable to forward Intra-BSS Rx packets when
4054 * ap_isolate=1 in hostapd.conf
4055 */
Yun Park046101c2016-09-02 15:32:14 -07004056 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004057 /*
4058 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4059 * all Rx packets to IPA uC, which need to be forwarded
4060 * to other interface.
4061 * And, IPA driver will send back to WLAN host driver
4062 * through exception pipe with fw_desc field set by FW.
4063 * Here we are checking fw_desc field for FORWARD bit
4064 * set, and forward to Tx. Then copy to kernel stack
4065 * only when DISCARD bit is not set.
4066 */
4067 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004068 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4069 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4070 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004071 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004072 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004073 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004074 "Intra-BSS FWD is disabled-skip forward to Tx");
4075 }
4076
4077 hdd_ipa_send_skb_to_network(skb, adapter);
4078 break;
4079
4080 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304081 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004082 "w2i cb wrong event: 0x%x", evt);
4083 return;
4084 }
4085}
4086
4087/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004088 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4089 * @priv: pointer to private data registered with IPA (we register a
4090 * pointer to the global IPA context)
4091 * @evt: the IPA event which triggered the callback
4092 * @data: data associated with the event
4093 *
4094 * Return: None
4095 */
4096static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
4097 unsigned long data)
4098{
4099 cds_ssr_protect(__func__);
4100 __hdd_ipa_w2i_cb(priv, evt, data);
4101 cds_ssr_unprotect(__func__);
4102}
4103
4104/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004105 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4106 * @skb: packet buffer which was transmitted
4107 *
4108 * Return: None
4109 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304110void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004111{
4112 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park52b2b992016-09-22 15:49:51 -07004113 struct ipa_rx_data *ipa_tx_desc;
4114 struct hdd_ipa_tx_desc *tx_desc;
4115 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004116
Yun Park52b2b992016-09-22 15:49:51 -07004117 if (!qdf_nbuf_ipa_owned_get(skb)) {
4118 dev_kfree_skb_any(skb);
4119 return;
4120 }
4121
4122 /* Get Tx desc pointer from SKB CB */
4123 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4124 tx_desc = hdd_ipa->tx_desc_list + id;
4125 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4126
4127 /* Return Tx Desc to IPA */
4128 ipa_free_skb(ipa_tx_desc);
4129
4130 /* Return to free tx desc list */
4131 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4132 tx_desc->ipa_tx_desc_ptr = NULL;
4133 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4134 hdd_ipa->stats.num_tx_desc_q_cnt--;
4135 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004136
4137 hdd_ipa->stats.num_tx_comp_cnt++;
4138
4139 atomic_dec(&hdd_ipa->tx_ref_cnt);
4140
4141 hdd_ipa_rm_try_release(hdd_ipa);
4142}
4143
4144/**
4145 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4146 * @iface_context: interface-specific IPA context
4147 * @ipa_tx_desc: packet data descriptor
4148 *
4149 * Return: None
4150 */
4151static void hdd_ipa_send_pkt_to_tl(
4152 struct hdd_ipa_iface_context *iface_context,
4153 struct ipa_rx_data *ipa_tx_desc)
4154{
4155 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004156 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304157 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004158 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004159
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304160 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004161 adapter = iface_context->adapter;
4162 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304163 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004164 ipa_free_skb(ipa_tx_desc);
4165 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304166 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004167 hdd_ipa_rm_try_release(hdd_ipa);
4168 return;
4169 }
4170
4171 /*
4172 * During CAC period, data packets shouldn't be sent over the air so
4173 * drop all the packets here
4174 */
hqu70708ab2017-10-10 17:52:01 +08004175 if (QDF_SAP_MODE == adapter->device_mode ||
4176 QDF_P2P_GO_MODE == adapter->device_mode) {
4177 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4178 ipa_free_skb(ipa_tx_desc);
4179 qdf_spin_unlock_bh(&iface_context->interface_lock);
4180 iface_context->stats.num_tx_cac_drop++;
4181 hdd_ipa_rm_try_release(hdd_ipa);
4182 return;
4183 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004184 }
4185
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004186 ++adapter->stats.tx_packets;
4187
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304188 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004189
4190 skb = ipa_tx_desc->skb;
4191
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304192 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004193
4194 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304195 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004196 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304197 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004198 ipa_tx_desc->dma_addr
4199 + HDD_IPA_WLAN_FRAG_HEADER
4200 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004201 ipa_tx_desc->skb->len -=
4202 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4203 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304204 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004205
Yun Park52b2b992016-09-22 15:49:51 -07004206 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4207 /* get free Tx desc and assign ipa_tx_desc pointer */
4208 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4209 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4210 struct hdd_ipa_tx_desc, link);
4211 list_del(&tx_desc->link);
4212 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4213 hdd_ipa->stats.num_tx_desc_q_cnt++;
4214 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4215 /* Store Tx Desc index into SKB CB */
4216 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4217 } else {
4218 hdd_ipa->stats.num_tx_desc_error++;
4219 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4220 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "No free Tx desc!");
4221 ipa_free_skb(ipa_tx_desc);
4222 hdd_ipa_rm_try_release(hdd_ipa);
4223 return;
4224 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004225
4226 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
4227
Leo Changfdb45c32016-10-28 11:09:23 -07004228 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004229 (struct cdp_vdev *)iface_context->tl_context,
4230 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004231 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304232 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
jiad05c1e812017-08-01 16:48:52 +08004233 qdf_nbuf_free(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004234 iface_context->stats.num_tx_err++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004235 return;
4236 }
4237
4238 atomic_inc(&hdd_ipa->tx_ref_cnt);
4239
4240 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004241}
4242
4243/**
Leo Chang11545d62016-10-17 14:53:50 -07004244 * hdd_ipa_is_present() - get IPA hw status
4245 * @hdd_ctx: pointer to hdd context
4246 *
4247 * ipa_uc_reg_rdyCB is not directly designed to check
4248 * ipa hw status. This is an undocumented function which
4249 * has confirmed with IPA team.
4250 *
4251 * Return: true - ipa hw present
4252 * false - ipa hw not present
4253 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004254bool hdd_ipa_is_present(struct hdd_context *hdd_ctx)
Leo Chang11545d62016-10-17 14:53:50 -07004255{
4256 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004257 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004258 return true;
4259 else
4260 return false;
4261}
4262
4263/**
Leo Chang69c39692016-10-12 20:11:12 -07004264 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004265 * @work: pointer to the scheduled work
4266 *
4267 * Called during PM resume to send packets to TL which were queued
4268 * while host was in the process of suspending.
4269 *
4270 * Return: None
4271 */
Leo Chang69c39692016-10-12 20:11:12 -07004272static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004273{
4274 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4275 struct hdd_ipa_priv,
4276 pm_work);
4277 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304278 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004279 uint32_t dequeued = 0;
4280
Leo Chang69c39692016-10-12 20:11:12 -07004281 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4282 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304283 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304284 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4285 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304286 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004287
4288 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004289 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004290 if (pm_tx_cb->exception) {
4291 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4292 "FLUSH EXCEPTION");
Govind Singh1dab23b2017-08-12 13:31:00 +05304293 if (pm_tx_cb->adapter->dev)
4294 hdd_softap_hard_start_xmit(skb,
4295 pm_tx_cb->adapter->dev);
Govind Singh02075942017-08-15 11:13:28 +05304296 else
4297 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004298 } else {
4299 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004300 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004301 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304302 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004303 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304304 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004305 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4306 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004307
4308 hdd_ipa->stats.num_tx_dequeued += dequeued;
4309 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4310 hdd_ipa->stats.num_max_pm_queue = dequeued;
4311}
4312
4313/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004314 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004315 * @priv: pointer to private data registered with IPA (we register a
4316 * pointer to the interface-specific IPA context)
4317 * @evt: the IPA event which triggered the callback
4318 * @data: data associated with the event
4319 *
4320 * Return: None
4321 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004322static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004323 unsigned long data)
4324{
4325 struct hdd_ipa_priv *hdd_ipa = NULL;
4326 struct ipa_rx_data *ipa_tx_desc;
4327 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304328 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004329 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304330 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004331
Mukul Sharma81661ae2015-10-30 20:26:02 +05304332 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004333 ipa_tx_desc = (struct ipa_rx_data *)data;
4334 hdd_ipa = iface_context->hdd_ipa;
4335
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004337 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4338 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004339 iface_context->stats.num_tx_drop++;
4340 return;
4341 }
4342
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004343 /*
4344 * When SSR is going on or driver is unloading, just drop the packets.
4345 * During SSR, there is no use in queueing the packets as STA has to
4346 * connect back any way
4347 */
4348 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304349 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004350 ipa_free_skb(ipa_tx_desc);
4351 iface_context->stats.num_tx_drop++;
4352 return;
4353 }
4354
4355 skb = ipa_tx_desc->skb;
4356
Yun Parkb187d542016-11-14 18:10:04 -08004357 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4358 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004359
4360 /*
4361 * If PROD resource is not requested here then there may be cases where
4362 * IPA hardware may be clocked down because of not having proper
4363 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4364 * workaround to request PROD resource while data is going over CONS
4365 * pipe to prevent the IPA hardware clockdown.
4366 */
4367 hdd_ipa_rm_request(hdd_ipa);
4368
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304369 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370 /*
4371 * If host is still suspended then queue the packets and these will be
4372 * drained later when resume completes. When packet is arrived here and
4373 * host is suspended, this means that there is already resume is in
4374 * progress.
4375 */
4376 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304377 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004378 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4379 pm_tx_cb->iface_context = iface_context;
4380 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304381 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004382 hdd_ipa->stats.num_tx_queued++;
4383
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304384 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004385 return;
4386 }
4387
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304388 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004389
4390 /*
4391 * If we are here means, host is not suspended, wait for the work queue
4392 * to finish.
4393 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004394 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004395
4396 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4397}
4398
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004399/*
4400 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4401 * @priv: pointer to private data registered with IPA (we register a
4402 * pointer to the interface-specific IPA context)
4403 * @evt: the IPA event which triggered the callback
4404 * @data: data associated with the event
4405 *
4406 * Return: None
4407 */
4408static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
4409 unsigned long data)
4410{
4411 cds_ssr_protect(__func__);
4412 __hdd_ipa_i2w_cb(priv, evt, data);
4413 cds_ssr_unprotect(__func__);
4414}
4415
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004416/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004417 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004418 * @hdd_ctx: Global HDD context
4419 *
4420 * Return: 0 on success, negativer errno on error
4421 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004422static int __hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004424 struct hdd_ipa_priv *hdd_ipa;
4425
4426 if (wlan_hdd_validate_context(hdd_ctx))
4427 return 0;
4428
4429 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430
4431 if (!hdd_ipa_is_enabled(hdd_ctx))
4432 return 0;
4433
4434 /*
4435 * Check if IPA is ready for suspend, If we are here means, there is
4436 * high chance that suspend would go through but just to avoid any race
4437 * condition after suspend started, these checks are conducted before
4438 * allowing to suspend.
4439 */
4440 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4441 return -EAGAIN;
4442
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304443 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004444
4445 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304446 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004447 return -EAGAIN;
4448 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304449 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004450
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304451 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004452 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304453 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004454
4455 return 0;
4456}
4457
4458/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004459 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4460 * @hdd_ctx: Global HDD context
4461 *
4462 * Return: 0 on success, negativer errno on error
4463 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004464int hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004465{
4466 int ret;
4467
4468 cds_ssr_protect(__func__);
4469 ret = __hdd_ipa_suspend(hdd_ctx);
4470 cds_ssr_unprotect(__func__);
4471
4472 return ret;
4473}
4474
4475/**
4476 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004477 * hdd_ctx: Global HDD context
4478 *
4479 * Return: 0 on success, negative errno on error
4480 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004481static int __hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004482{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004483 struct hdd_ipa_priv *hdd_ipa;
4484
4485 if (wlan_hdd_validate_context(hdd_ctx))
4486 return 0;
4487
4488 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004489
4490 if (!hdd_ipa_is_enabled(hdd_ctx))
4491 return 0;
4492
4493 schedule_work(&hdd_ipa->pm_work);
4494
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304495 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004496 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304497 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498
4499 return 0;
4500}
4501
4502/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004503 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4504 * hdd_ctx: Global HDD context
4505 *
4506 * Return: 0 on success, negative errno on error
4507 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004508int hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004509{
4510 int ret;
4511
4512 cds_ssr_protect(__func__);
4513 ret = __hdd_ipa_resume(hdd_ctx);
4514 cds_ssr_unprotect(__func__);
4515
4516 return ret;
4517}
4518
4519/**
Yun Park52b2b992016-09-22 15:49:51 -07004520 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
4521 * @hdd_ipa: Global HDD IPA context
4522 *
4523 * Return: 0 on success, negative errno on error
4524 */
4525static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
4526{
4527 int i;
4528 uint32_t max_desc_cnt;
4529 struct hdd_ipa_tx_desc *tmp_desc;
jiad14fe4fb2017-08-08 13:33:14 +08004530 struct ol_txrx_pdev_t *pdev;
Yun Park52b2b992016-09-22 15:49:51 -07004531
jiad14fe4fb2017-08-08 13:33:14 +08004532 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
4533 if (!pdev) {
4534 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "pdev is NULL");
4535 return -ENODEV;
4536 }
4537
4538 hdd_ipa->tx_desc_size = QDF_MIN(
4539 hdd_ipa->hdd_ctx->config->IpaMccTxDescSize,
4540 pdev->tx_desc.pool_size);
Yun Park52b2b992016-09-22 15:49:51 -07004541
4542 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
4543
jiad14fe4fb2017-08-08 13:33:14 +08004544 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc) *
4545 hdd_ipa->tx_desc_size);
Yun Park52b2b992016-09-22 15:49:51 -07004546
4547 if (!tmp_desc) {
4548 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4549 "Free Tx descriptor allocation failed");
4550 return -ENOMEM;
4551 }
4552
4553 hdd_ipa->tx_desc_list = tmp_desc;
4554
4555 qdf_spin_lock_bh(&hdd_ipa->q_lock);
jiad14fe4fb2017-08-08 13:33:14 +08004556 for (i = 0; i < hdd_ipa->tx_desc_size; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07004557 tmp_desc->id = i;
4558 tmp_desc->ipa_tx_desc_ptr = NULL;
4559 list_add_tail(&tmp_desc->link,
4560 &hdd_ipa->free_tx_desc_head);
4561 tmp_desc++;
4562 }
4563
4564 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4565 hdd_ipa->stats.num_tx_desc_error = 0;
4566
4567 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4568
4569 return 0;
4570}
4571
4572/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004573 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4574 * @hdd_ipa: Global HDD IPA context
4575 *
4576 * Return: 0 on success, negative errno on error
4577 */
4578static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4579{
4580 int i, ret = 0;
4581 struct ipa_sys_connect_params *ipa;
4582 uint32_t desc_fifo_sz;
4583
4584 /* The maximum number of descriptors that can be provided to a BAM at
4585 * once is one less than the total number of descriptors that the buffer
4586 * can contain.
4587 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4588 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4589 * be provided at once.
4590 * Because of above requirement, one extra descriptor will be added to
4591 * make sure hardware always has one descriptor.
4592 */
4593 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4594 + sizeof(struct sps_iovec);
4595
4596 /*setup TX pipes */
4597 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4598 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4599
4600 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4601 ipa->desc_fifo_sz = desc_fifo_sz;
4602 ipa->priv = &hdd_ipa->iface_context[i];
4603 ipa->notify = hdd_ipa_i2w_cb;
4604
4605 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4606 ipa->ipa_ep_cfg.hdr.hdr_len =
4607 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4608 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4609 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4610 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4611 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4612 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4613 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4614 } else {
4615 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4616 }
4617 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4618
4619 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4620 ipa->keep_ipa_awake = 1;
4621
4622 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4623 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004624 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4625 "Failed for pipe %d ret: %d", i, ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004626 goto setup_sys_pipe_fail;
4627 }
4628 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4629 }
4630
4631 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4632 /*
4633 * Hard code it here, this can be extended if in case
4634 * PROD pipe is also per interface.
4635 * Right now there is no advantage of doing this.
4636 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4638
Yun Parkb4f591d2017-03-29 15:51:01 -07004639 ipa->client = IPA_CLIENT_WLAN1_PROD;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640
4641 ipa->desc_fifo_sz = desc_fifo_sz;
4642 ipa->priv = hdd_ipa;
4643 ipa->notify = hdd_ipa_w2i_cb;
4644
4645 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4646 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4647 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4648 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4649
4650 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4651 ipa->keep_ipa_awake = 1;
4652
4653 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4654 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304655 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004656 "Failed for RX pipe: %d", ret);
4657 goto setup_sys_pipe_fail;
4658 }
4659 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4660 }
4661
jiad14fe4fb2017-08-08 13:33:14 +08004662 /* Allocate free Tx desc list */
Yun Park52b2b992016-09-22 15:49:51 -07004663 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
4664 if (ret)
4665 goto setup_sys_pipe_fail;
4666
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004667 return ret;
4668
4669setup_sys_pipe_fail:
4670
4671 while (--i >= 0) {
4672 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304673 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004674 sizeof(struct hdd_ipa_sys_pipe));
4675 }
4676
4677 return ret;
4678}
4679
4680/**
4681 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4682 * @hdd_ipa: Global HDD IPA context
4683 *
4684 * Return: None
4685 */
4686static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4687{
4688 int ret = 0, i;
Yun Park52b2b992016-09-22 15:49:51 -07004689 struct hdd_ipa_tx_desc *tmp_desc;
4690 struct ipa_rx_data *ipa_tx_desc;
4691
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004692 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4693 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
Yun Parkb4f591d2017-03-29 15:51:01 -07004694 ret = ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4695 conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004696 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304697 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004698 ret);
4699
4700 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4701 }
4702 }
Yun Park52b2b992016-09-22 15:49:51 -07004703
4704 if (hdd_ipa->tx_desc_list) {
Yun Park52b2b992016-09-22 15:49:51 -07004705 qdf_spin_lock_bh(&hdd_ipa->q_lock);
jiad14fe4fb2017-08-08 13:33:14 +08004706 for (i = 0; i < hdd_ipa->tx_desc_size; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07004707 tmp_desc = hdd_ipa->tx_desc_list + i;
4708 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
4709 if (ipa_tx_desc)
4710 ipa_free_skb(ipa_tx_desc);
4711 }
4712 tmp_desc = hdd_ipa->tx_desc_list;
4713 hdd_ipa->tx_desc_list = NULL;
4714 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4715 hdd_ipa->stats.num_tx_desc_error = 0;
4716 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4717 qdf_mem_free(tmp_desc);
4718 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004719}
4720
4721/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004722 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4723 * @iface_context: interface-specific IPA context
4724 *
4725 * Return: None
4726 */
4727static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4728{
Yun Parkfec73dc2017-09-06 10:40:07 -07004729 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
4730
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004731 if (iface_context == NULL)
4732 return;
4733
Yun Parkb4f591d2017-03-29 15:51:01 -07004734 cdp_ipa_cleanup_iface(cds_get_context(QDF_MODULE_ID_SOC),
4735 iface_context->adapter->dev->name,
4736 hdd_ipa_is_ipv6_enabled(iface_context->hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004737
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304738 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004739 iface_context->adapter->ipa_context = NULL;
4740 iface_context->adapter = NULL;
4741 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304742 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004743 iface_context->ifa_address = 0;
4744 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304745 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004746 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304747 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004748 }
4749 iface_context->hdd_ipa->num_iface--;
Yun Parkfec73dc2017-09-06 10:40:07 -07004750 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: num_iface=%d",
4751 iface_context->hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004752}
4753
4754/**
4755 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4756 * @hdd_ipa: HDD IPA global context
4757 * @adapter: Interface upon which IPA is being setup
4758 * @sta_id: Station ID of the API instance
4759 *
4760 * Return: 0 on success, negative errno value on error
4761 */
4762static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004763 struct hdd_adapter *adapter, uint8_t sta_id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004764{
4765 struct hdd_ipa_iface_context *iface_context = NULL;
4766 void *tl_context = NULL;
4767 int i, ret = 0;
4768
Yun Parkfec73dc2017-09-06 10:40:07 -07004769 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
4770
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004771 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4772 * channel change indication. Since these indications are sent by lower
4773 * layer as SAP updates and IPA doesn't have to do anything for these
4774 * updates so ignoring!
4775 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004776 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004777 return 0;
4778
4779 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4780 if (hdd_ipa->iface_context[i].adapter == NULL) {
4781 iface_context = &(hdd_ipa->iface_context[i]);
4782 break;
4783 }
4784 }
4785
4786 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304787 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004788 "All the IPA interfaces are in use");
4789 ret = -ENOMEM;
4790 goto end;
4791 }
4792
4793 adapter->ipa_context = iface_context;
4794 iface_context->adapter = adapter;
4795 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004796 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07004797 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004798 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304799 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004800 "Not able to get TL context sta_id: %d", sta_id);
4801 ret = -EINVAL;
4802 goto end;
4803 }
4804
4805 iface_context->tl_context = tl_context;
4806
Yun Parkb4f591d2017-03-29 15:51:01 -07004807 ret = cdp_ipa_setup_iface(cds_get_context(QDF_MODULE_ID_SOC),
4808 adapter->dev->name, adapter->dev->dev_addr,
4809 iface_context->prod_client,
4810 iface_context->cons_client,
4811 adapter->sessionId,
4812 hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004813 if (ret)
4814 goto end;
4815
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004816 hdd_ipa->num_iface++;
Yun Parkfec73dc2017-09-06 10:40:07 -07004817
4818 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: num_iface=%d",
4819 hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004820 return ret;
4821
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004822end:
4823 if (iface_context)
4824 hdd_ipa_cleanup_iface(iface_context);
4825 return ret;
4826}
4827
Yun Parka27049a2016-10-11 12:30:49 -07004828#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004829/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004830 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Jeff Johnson4929cd92017-10-06 19:21:57 -07004831 * @hdd_ctx: HDD context
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004832 * @mcc_mode: 0=MCC/1=SCC
4833 *
4834 * Return: 0 on success, negative errno value on error
4835 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07004836static int __hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx,
4837 bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004838{
4839 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304840 QDF_STATUS status;
Jeff Johnson089d0432017-10-02 13:27:21 -07004841 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004842 struct ipa_msg_meta meta;
4843 struct ipa_wlan_msg *msg;
4844 int ret;
4845
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004846 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004847 return -EINVAL;
4848
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004849 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4850 return -EINVAL;
4851
4852 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004853 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004854 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304855 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Jeff Johnson089d0432017-10-02 13:27:21 -07004856 adapter = adapter_node->adapter;
4857 if (adapter->device_mode == QDF_STA_MODE ||
4858 adapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004859 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnson089d0432017-10-02 13:27:21 -07004860 adapter->device_mode);
4861 hdd_deinit_tx_rx(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004862 }
4863 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004864 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004865 adapter_node = next;
4866 }
4867 }
4868
4869 /* Send SCC/MCC Switching event to IPA */
4870 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304871 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004872 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004873 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004874 return -ENOMEM;
4875 }
4876
4877 meta.msg_type = mcc_mode ?
4878 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Srinivas Girigowda97852372017-03-06 16:52:59 -08004879 hdd_debug("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004880
4881 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4882
4883 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004884 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004885 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304886 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004887 }
4888
4889 return ret;
4890}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004891
4892/**
4893 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4894 * @mcc_mode: 0=MCC/1=SCC
4895 *
4896 * Return: 0 on success, negative errno value on error
4897 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004898int hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx, bool mcc_mode)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004899{
4900 int ret;
4901
4902 cds_ssr_protect(__func__);
4903 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4904 cds_ssr_unprotect(__func__);
4905
4906 return ret;
4907}
Yun Parka27049a2016-10-11 12:30:49 -07004908#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004909
4910/**
4911 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4912 * @event: IPA WLAN event to be converted to a string
4913 *
4914 * Return: ASCII string representing the IPA WLAN event
4915 */
4916static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4917{
4918 switch (event) {
4919 case WLAN_CLIENT_CONNECT:
4920 return "WLAN_CLIENT_CONNECT";
4921 case WLAN_CLIENT_DISCONNECT:
4922 return "WLAN_CLIENT_DISCONNECT";
4923 case WLAN_CLIENT_POWER_SAVE_MODE:
4924 return "WLAN_CLIENT_POWER_SAVE_MODE";
4925 case WLAN_CLIENT_NORMAL_MODE:
4926 return "WLAN_CLIENT_NORMAL_MODE";
4927 case SW_ROUTING_ENABLE:
4928 return "SW_ROUTING_ENABLE";
4929 case SW_ROUTING_DISABLE:
4930 return "SW_ROUTING_DISABLE";
4931 case WLAN_AP_CONNECT:
4932 return "WLAN_AP_CONNECT";
4933 case WLAN_AP_DISCONNECT:
4934 return "WLAN_AP_DISCONNECT";
4935 case WLAN_STA_CONNECT:
4936 return "WLAN_STA_CONNECT";
4937 case WLAN_STA_DISCONNECT:
4938 return "WLAN_STA_DISCONNECT";
4939 case WLAN_CLIENT_CONNECT_EX:
4940 return "WLAN_CLIENT_CONNECT_EX";
4941
4942 case IPA_WLAN_EVENT_MAX:
4943 default:
4944 return "UNKNOWN";
4945 }
4946}
4947
4948/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004949 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4950 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4951 *
4952 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4953 */
4954static enum ipa_wlan_event
4955hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4956{
4957 enum ipa_wlan_event ipa_event;
4958
4959 switch (hdd_ipa_event_type) {
4960 case HDD_IPA_CLIENT_CONNECT:
4961 ipa_event = WLAN_CLIENT_CONNECT;
4962 break;
4963 case HDD_IPA_CLIENT_DISCONNECT:
4964 ipa_event = WLAN_CLIENT_DISCONNECT;
4965 break;
4966 case HDD_IPA_AP_CONNECT:
4967 ipa_event = WLAN_AP_CONNECT;
4968 break;
4969 case HDD_IPA_AP_DISCONNECT:
4970 ipa_event = WLAN_AP_DISCONNECT;
4971 break;
4972 case HDD_IPA_STA_CONNECT:
4973 ipa_event = WLAN_STA_CONNECT;
4974 break;
4975 case HDD_IPA_STA_DISCONNECT:
4976 ipa_event = WLAN_STA_DISCONNECT;
4977 break;
4978 case HDD_IPA_CLIENT_CONNECT_EX:
4979 ipa_event = WLAN_CLIENT_CONNECT_EX;
4980 break;
4981 case HDD_IPA_WLAN_EVENT_MAX:
4982 default:
4983 ipa_event = IPA_WLAN_EVENT_MAX;
4984 break;
4985 }
4986 return ipa_event;
4987
4988}
4989
4990/**
4991 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004992 * @adapter: adapter upon which the event was received
4993 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004994 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004995 * @mac_address: MAC address associated with the event
4996 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004997 * This function is meant to be called from within wlan_hdd_ipa.c
4998 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999 * Return: 0 on success, negative errno value on error
5000 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005001static int __hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005002 enum ipa_wlan_event type, uint8_t *mac_addr)
5003{
5004 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
5005 struct ipa_msg_meta meta;
5006 struct ipa_wlan_msg *msg;
5007 struct ipa_wlan_msg_ex *msg_ex = NULL;
5008 int ret;
5009
Yun Parkfec73dc2017-09-06 10:40:07 -07005010 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005011 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5012 mac_addr, sta_id);
5013
5014 if (type >= IPA_WLAN_EVENT_MAX)
5015 return -EINVAL;
5016
5017 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5018 return -EINVAL;
5019
5020 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305021 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005022 return -EINVAL;
5023 }
5024
5025 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5026 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005027 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005028 return 0;
5029 }
5030
5031 /*
5032 * During IPA UC resource loading/unloading new events can be issued.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005033 */
Yun Park777d7242017-03-30 15:38:33 -07005034 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5035 (hdd_ipa->resource_loading || hdd_ipa->resource_unloading)) {
5036 unsigned int pending_event_count;
5037 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005038
Yun Park777d7242017-03-30 15:38:33 -07005039 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5040 "%s:IPA resource %s inprogress",
5041 hdd_ipa_wlan_event_to_str(type),
5042 hdd_ipa->resource_loading ?
5043 "load" : "unload");
5044
5045 /* Wait until completion of the long/unloading */
5046 ret = wait_for_completion_timeout(&hdd_ipa->ipa_resource_comp,
5047 msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME));
5048 if (!ret) {
5049 /*
5050 * If timed out, store the events separately and
5051 * handle them later.
5052 */
Yun Park64c405e2017-01-10 22:35:51 -08005053 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park777d7242017-03-30 15:38:33 -07005054 "IPA resource %s timed out",
5055 hdd_ipa->resource_loading ?
5056 "load" : "unload");
Yun Park7c4f31b2016-11-30 10:09:21 -08005057
Yun Park777d7242017-03-30 15:38:33 -07005058 if (hdd_ipa->resource_loading) {
5059 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005060
Yun Park777d7242017-03-30 15:38:33 -07005061 pending_event_count =
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005062 qdf_list_size(&hdd_ipa->pending_event);
Yun Park777d7242017-03-30 15:38:33 -07005063 if (pending_event_count >=
5064 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
5065 hdd_debug(
5066 "Reached max pending event count");
5067 qdf_list_remove_front(
5068 &hdd_ipa->pending_event,
5069 (qdf_list_node_t **)&pending_event);
5070 } else {
5071 pending_event =
5072 (struct ipa_uc_pending_event *)
5073 qdf_mem_malloc(sizeof(
5074 struct ipa_uc_pending_event));
5075 }
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005076
Yun Park777d7242017-03-30 15:38:33 -07005077 if (!pending_event) {
5078 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5079 "Pending event memory alloc fail");
5080 qdf_mutex_release(&hdd_ipa->ipa_lock);
5081 return -ENOMEM;
5082 }
5083
5084 pending_event->adapter = adapter;
5085 pending_event->sta_id = sta_id;
5086 pending_event->type = type;
5087 qdf_mem_copy(pending_event->mac_addr,
5088 mac_addr, QDF_MAC_ADDR_SIZE);
5089 qdf_list_insert_back(&hdd_ipa->pending_event,
5090 &pending_event->node);
5091
Yun Park64c405e2017-01-10 22:35:51 -08005092 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005093 }
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005094 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005095 }
Jeff Johnson4929cd92017-10-06 19:21:57 -07005096 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5097 "IPA resource %s completed",
5098 hdd_ipa->resource_loading ?
5099 "load" : "unload");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005100 }
5101
5102 hdd_ipa->stats.event[type]++;
5103
Leo Chang3bc8fed2015-11-13 10:59:47 -08005104 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005105 switch (type) {
5106 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005107 qdf_mutex_acquire(&hdd_ipa->event_lock);
5108
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005109 /* STA already connected and without disconnect, connect again
5110 * This is Roaming scenario
5111 */
5112 if (hdd_ipa->sta_connected)
5113 hdd_ipa_cleanup_iface(adapter->ipa_context);
5114
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005115 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5116 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305117 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005118 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005119 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005120
Yun Park8f289c82016-10-18 16:38:21 -07005121 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5122 (hdd_ipa->sap_num_connected_sta > 0) &&
5123 !hdd_ipa->sta_connected) {
5124 qdf_mutex_release(&hdd_ipa->event_lock);
5125 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005126 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005127 qdf_mutex_acquire(&hdd_ipa->event_lock);
5128 }
5129
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005130 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005131 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005132 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005133
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005134 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005135
5136 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005137
5138 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "sta_connected=%d",
5139 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005140 break;
5141
5142 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005143 qdf_mutex_acquire(&hdd_ipa->event_lock);
5144
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005145 /* For DFS channel we get two start_bss event (before and after
5146 * CAC). Also when ACS range includes both DFS and non DFS
5147 * channels, we could possibly change channel many times due to
5148 * RADAR detection and chosen channel may not be a DFS channels.
5149 * So dont return error here. Just discard the event.
5150 */
Yun Park8f289c82016-10-18 16:38:21 -07005151 if (adapter->ipa_context) {
5152 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005153 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005154 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005155
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005156 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5157 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005158 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005159 hdd_err("%s: Evt: %d, Interface setup failed",
5160 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005161 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005162 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005163
Yun Park8f289c82016-10-18 16:38:21 -07005164 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5165 qdf_mutex_release(&hdd_ipa->event_lock);
5166 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005167 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005168 qdf_mutex_acquire(&hdd_ipa->event_lock);
5169 }
5170
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005171 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005172 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005173 (adapter->ipa_context))->iface_id;
5174
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305175 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005176 break;
5177
5178 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305179 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005180
5181 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005182 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005183 hdd_err("%s: Evt: %d, STA already disconnected",
5184 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005185 return -EINVAL;
5186 }
Yun Parka37592b2016-06-11 17:10:28 -07005187
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005188 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005189
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005190 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005191 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005192 msg_ex->name);
5193 } else {
5194 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005195 if (!hdd_ipa->num_iface &&
5196 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305197 hdd_ipa->activated_fw_pipe) &&
5198 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005199 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005200 }
5201
Yun Park74127cf2016-09-18 11:22:41 -07005202 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5203 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005204 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005205 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005206 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005207 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005208 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5209 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005210 }
5211
Yun Park8f289c82016-10-18 16:38:21 -07005212 hdd_ipa_cleanup_iface(adapter->ipa_context);
5213
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305214 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005215
5216 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "sta_connected=%d",
5217 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005218 break;
5219
5220 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005221 qdf_mutex_acquire(&hdd_ipa->event_lock);
5222
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005223 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005224 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005225 hdd_err("%s: Evt: %d, SAP already disconnected",
5226 msg_ex->name, meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005227 return -EINVAL;
5228 }
5229
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005230 if ((!hdd_ipa->num_iface) &&
5231 (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305232 hdd_ipa->activated_fw_pipe) &&
5233 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005234 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005235 /*
5236 * We disable WDI pipes directly here since
5237 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5238 * processed when unloading WLAN driver is in
5239 * progress
5240 */
5241 hdd_ipa_uc_disable_pipes(hdd_ipa);
5242 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305243 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005244 "NO INTF left but still pipe clean up");
5245 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5246 }
5247 }
5248
5249 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005250 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005251 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005252 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005253 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005254 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5255 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005256 }
Yun Parka37592b2016-06-11 17:10:28 -07005257
Yun Park8f289c82016-10-18 16:38:21 -07005258 hdd_ipa_cleanup_iface(adapter->ipa_context);
5259
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305260 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005261 break;
5262
5263 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005264 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005265 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005266 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305267 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005268 return 0;
5269 }
5270
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305271 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005272 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5273 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005274 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305275 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005276 "%s: STA ID %d found, not valid",
5277 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005278 return 0;
5279 }
Yun Park312f71a2015-12-08 10:22:42 -08005280
5281 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005282 if (hdd_ipa->sap_num_connected_sta == 0 &&
5283 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005284 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005285 hdd_ipa->sta_connected) {
5286 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005287 hdd_ipa_uc_offload_enable_disable(
5288 hdd_get_adapter(hdd_ipa->hdd_ctx,
5289 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005290 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005291 qdf_mutex_acquire(&hdd_ipa->event_lock);
5292 }
Yun Parka37592b2016-06-11 17:10:28 -07005293
Yun Park312f71a2015-12-08 10:22:42 -08005294 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5295 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305296 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005297 "%s: handle 1st con ret %d",
5298 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005299
5300 if (hdd_ipa_uc_sta_is_enabled(
5301 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005302 hdd_ipa->sta_connected) {
5303 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005304 hdd_ipa_uc_offload_enable_disable(
5305 hdd_get_adapter(
5306 hdd_ipa->hdd_ctx,
5307 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005308 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005309 } else {
5310 qdf_mutex_release(&hdd_ipa->event_lock);
5311 }
Yun Parka37592b2016-06-11 17:10:28 -07005312
Yun Park312f71a2015-12-08 10:22:42 -08005313 return ret;
5314 }
5315 }
5316
5317 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005318
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305319 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005320
5321 meta.msg_type = type;
5322 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5323 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305324 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005325
5326 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305327 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005328 "msg_ex allocation failed");
5329 return -ENOMEM;
5330 }
5331 strlcpy(msg_ex->name, adapter->dev->name,
5332 IPA_RESOURCE_NAME_MAX);
5333 msg_ex->num_of_attribs = 1;
5334 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5335 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5336 msg_ex->attribs[0].offset =
5337 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5338 } else {
5339 msg_ex->attribs[0].offset =
5340 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5341 }
5342 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5343 IPA_MAC_ADDR_SIZE);
5344
5345 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5346
5347 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005348 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305349 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305350 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005351 return ret;
5352 }
5353 hdd_ipa->stats.num_send_msg++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005354
5355 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "sap_num_connected_sta=%d",
5356 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005357 return ret;
5358
5359 case WLAN_CLIENT_DISCONNECT:
5360 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005361 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005362 "%s: IPA UC OFFLOAD NOT ENABLED",
5363 msg_ex->name);
5364 return 0;
5365 }
5366
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305367 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Park73ea8bb2017-08-25 07:27:39 -07005368 if (!hdd_ipa->sap_num_connected_sta) {
5369 qdf_mutex_release(&hdd_ipa->event_lock);
5370 hdd_err("%s: Evt: %d, Client already disconnected",
5371 msg_ex->name, meta.msg_type);
5372 return 0;
5373 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005374 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005375 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305376 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005377 "%s: STA ID %d NOT found, not valid",
5378 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005379 return 0;
5380 }
5381 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005382
Yun Park9b5030f2016-11-08 12:02:37 -08005383 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005384 if (!hdd_ipa->sap_num_connected_sta &&
5385 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005386 if ((false == hdd_ipa->resource_unloading)
5387 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305388 hdd_ipa->activated_fw_pipe) &&
5389 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005390 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5391 }
5392
Yun Park9b5030f2016-11-08 12:02:37 -08005393 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jiad9d472c92017-07-28 14:05:31 +08005394 hdd_ipa->sta_connected) {
5395 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005396 hdd_ipa_uc_offload_enable_disable(
5397 hdd_get_adapter(hdd_ipa->hdd_ctx,
5398 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005399 SIR_STA_RX_DATA_OFFLOAD, false);
jiad9d472c92017-07-28 14:05:31 +08005400 } else {
5401 qdf_mutex_release(&hdd_ipa->event_lock);
5402 }
Yun Park8f289c82016-10-18 16:38:21 -07005403 } else {
5404 qdf_mutex_release(&hdd_ipa->event_lock);
5405 }
Yun Parkfec73dc2017-09-06 10:40:07 -07005406
5407 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "sap_num_connected_sta=%d",
5408 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005409 break;
5410
5411 default:
5412 return 0;
5413 }
5414
5415 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305416 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005417 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305418 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005419 return -ENOMEM;
5420 }
5421
5422 meta.msg_type = type;
5423 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5424 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5425
Srinivas Girigowda97852372017-03-06 16:52:59 -08005426 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005427 msg->name, meta.msg_type);
5428
5429 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5430
5431 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005432 hdd_err("%s: Evt: %d fail:%d",
5433 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305434 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005435 return ret;
5436 }
5437
5438 hdd_ipa->stats.num_send_msg++;
5439
5440end:
5441 return ret;
5442}
5443
5444/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005445 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005446 * @adapter: adapter upon which the event was received
5447 * @sta_id: station id for the event
5448 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5449 * @mac_address: MAC address associated with the event
5450 *
5451 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5452 *
5453 * Return: 0 on success, negative errno value on error
5454 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005455int hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005456 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5457{
5458 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005459 int ret = 0;
5460
5461 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005462
Leo Changa202b522016-10-14 16:13:50 -07005463 /* Data path offload only support for STA and SAP mode */
5464 if ((QDF_STA_MODE == adapter->device_mode) ||
5465 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005466 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005467
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005468 cds_ssr_unprotect(__func__);
5469
5470 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005471}
5472
5473/**
5474 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5475 * @hdd_ipa: Global HDD IPA context
5476 *
5477 * Return: None
5478 */
5479static void
5480hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5481{
5482 unsigned int pending_event_count;
5483 struct ipa_uc_pending_event *pending_event = NULL;
5484
5485 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005486 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005487 "%s, Pending Event Count %d", __func__, pending_event_count);
5488 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005489 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005490 "%s, No Pending Event", __func__);
5491 return;
5492 }
5493
5494 qdf_list_remove_front(&hdd_ipa->pending_event,
5495 (qdf_list_node_t **)&pending_event);
5496 while (pending_event != NULL) {
5497 __hdd_ipa_wlan_evt(pending_event->adapter,
5498 pending_event->type,
5499 pending_event->sta_id,
5500 pending_event->mac_addr);
5501 qdf_mem_free(pending_event);
5502 pending_event = NULL;
5503 qdf_list_remove_front(&hdd_ipa->pending_event,
5504 (qdf_list_node_t **)&pending_event);
5505 }
5506}
5507
5508/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005509 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5510 * @state: IPA RM state value
5511 *
5512 * Return: ASCII string representing the IPA RM state
5513 */
5514static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5515{
5516 switch (state) {
5517 case HDD_IPA_RM_RELEASED:
5518 return "RELEASED";
5519 case HDD_IPA_RM_GRANT_PENDING:
5520 return "GRANT_PENDING";
5521 case HDD_IPA_RM_GRANTED:
5522 return "GRANTED";
5523 }
5524
5525 return "UNKNOWN";
5526}
5527
5528/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005529 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005530 * @hdd_ctx: HDD global context
5531 *
5532 * Allocate hdd_ipa resources, ipa pipe resource and register
5533 * wlan interface with IPA module.
5534 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305535 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005536 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005537static QDF_STATUS __hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005538{
5539 struct hdd_ipa_priv *hdd_ipa = NULL;
5540 int ret, i;
5541 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005542 struct ol_txrx_pdev_t *pdev = NULL;
Yun Park66f24c42017-03-20 10:39:47 -07005543 struct ipa_rm_perf_profile profile;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005544
Yun Parkfec73dc2017-09-06 10:40:07 -07005545 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "enter");
5546
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005547 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305548 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005549
Yun Parkbaa62862017-01-18 13:43:34 -08005550 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005551 if (!pdev) {
5552 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5553 goto fail_return;
5554 }
5555
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305556 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005557 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305558 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005559 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005560 }
5561
5562 hdd_ctx->hdd_ipa = hdd_ipa;
5563 ghdd_ipa = hdd_ipa;
5564 hdd_ipa->hdd_ctx = hdd_ctx;
5565 hdd_ipa->num_iface = 0;
5566
5567 /* Create the interface context */
5568 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5569 iface_context = &hdd_ipa->iface_context[i];
5570 iface_context->hdd_ipa = hdd_ipa;
5571 iface_context->cons_client =
5572 hdd_ipa_adapter_2_client[i].cons_client;
5573 iface_context->prod_client =
5574 hdd_ipa_adapter_2_client[i].prod_client;
5575 iface_context->iface_id = i;
5576 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305577 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005578 }
5579 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005580 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5581 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005582 }
5583
Leo Chang69c39692016-10-12 20:11:12 -07005584 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305585 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07005586 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305587 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005588 qdf_list_create(&hdd_ipa->pending_event, 1000);
5589 qdf_mutex_create(&hdd_ipa->event_lock);
5590 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005591
5592 ret = hdd_ipa_setup_rm(hdd_ipa);
5593 if (ret)
5594 goto fail_setup_rm;
5595
5596 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5597 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305598 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005599 hdd_ipa->sap_num_connected_sta = 0;
5600 hdd_ipa->ipa_tx_packets_diff = 0;
5601 hdd_ipa->ipa_rx_packets_diff = 0;
5602 hdd_ipa->ipa_p_tx_packets = 0;
5603 hdd_ipa->ipa_p_rx_packets = 0;
5604 hdd_ipa->resource_loading = false;
5605 hdd_ipa->resource_unloading = false;
5606 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005607 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08005608 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005609 /* Setup IPA sys_pipe for MCC */
5610 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5611 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5612 if (ret)
5613 goto fail_create_sys_pipe;
5614 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005615 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5616 goto fail_create_sys_pipe;
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005617
5618 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5619 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
5620 hdd_ipa_uc_fw_op_event_handler);
5621 hdd_ipa->uc_op_work[i].msg = NULL;
5622 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005623 } else {
5624 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5625 if (ret)
5626 goto fail_create_sys_pipe;
5627 }
5628
Yun Park66f24c42017-03-20 10:39:47 -07005629 /* When IPA clock scaling is disabled, initialze maximum clock */
5630 if (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)) {
5631 profile.max_supported_bandwidth_mbps = 800;
5632 hdd_debug("IPA clock scaling is disabled.");
5633 hdd_debug("Set initial CONS/PROD perf: %d",
5634 profile.max_supported_bandwidth_mbps);
5635 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
5636 &profile);
5637 if (ret) {
5638 hdd_err("RM CONS set perf profile failed: %d", ret);
5639 goto fail_create_sys_pipe;
5640 }
5641
5642 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
5643 &profile);
5644 if (ret) {
5645 hdd_err("RM PROD set perf profile failed: %d", ret);
5646 goto fail_create_sys_pipe;
5647 }
5648 }
5649
Yun Park777d7242017-03-30 15:38:33 -07005650 init_completion(&hdd_ipa->ipa_resource_comp);
5651
Yun Parkfec73dc2017-09-06 10:40:07 -07005652 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305653 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005654
5655fail_create_sys_pipe:
5656 hdd_ipa_destroy_rm_resource(hdd_ipa);
5657fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305658 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305659 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005660 hdd_ctx->hdd_ipa = NULL;
5661 ghdd_ipa = NULL;
5662fail_return:
Yun Parkfec73dc2017-09-06 10:40:07 -07005663 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "exit: fail");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305664 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005665}
5666
5667/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005668 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5669 * @hdd_ctx: HDD global context
5670 *
5671 * Allocate hdd_ipa resources, ipa pipe resource and register
5672 * wlan interface with IPA module.
5673 *
5674 * Return: QDF_STATUS enumeration
5675 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005676QDF_STATUS hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005677{
5678 QDF_STATUS ret;
5679
5680 cds_ssr_protect(__func__);
5681 ret = __hdd_ipa_init(hdd_ctx);
5682 cds_ssr_unprotect(__func__);
5683
5684 return ret;
5685}
5686
Arun Khandavallicc544b32017-01-30 19:52:16 +05305687
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005688/**
Govind Singh1dab23b2017-08-12 13:31:00 +05305689 * __hdd_ipa_flush - flush IPA exception path SKB's
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005690 * @hdd_ctx: HDD global context
5691 *
Govind Singh1dab23b2017-08-12 13:31:00 +05305692 * Return: none
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005693 */
Govind Singh1dab23b2017-08-12 13:31:00 +05305694static void __hdd_ipa_flush(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005695{
5696 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305697 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005698 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5699
5700 if (!hdd_ipa_is_enabled(hdd_ctx))
Govind Singh1dab23b2017-08-12 13:31:00 +05305701 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005702
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005703 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005704
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305705 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005706
Nirav Shahcbc6d722016-03-01 16:24:53 +05305707 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5708 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305709 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005710
5711 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07005712 if (pm_tx_cb->ipa_tx_desc)
5713 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005714
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305715 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005716 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305717 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Govind Singh1dab23b2017-08-12 13:31:00 +05305718}
5719
5720/**
5721 * __hdd_ipa_cleanup - IPA cleanup function
5722 * @hdd_ctx: HDD global context
5723 *
5724 * Return: QDF_STATUS enumeration
5725 */
5726static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
5727{
5728 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5729 int i;
5730 struct hdd_ipa_iface_context *iface_context = NULL;
5731
5732 if (!hdd_ipa_is_enabled(hdd_ctx))
5733 return QDF_STATUS_SUCCESS;
5734
5735 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5736 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5737 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5738 }
5739
5740 /* Teardown IPA sys_pipe for MCC */
5741 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5742 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5743
5744 hdd_ipa_destroy_rm_resource(hdd_ipa);
5745
5746 __hdd_ipa_flush(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005747
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305748 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07005749 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005750
5751 /* destory the interface lock */
5752 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5753 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305754 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005755 }
5756
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005757 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08005758 if (ipa_uc_dereg_rdyCB())
5759 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5760 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005761 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305762 qdf_mutex_destroy(&hdd_ipa->event_lock);
5763 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07005764 qdf_list_destroy(&hdd_ipa->pending_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005765
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005766 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5767 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5768 hdd_ipa->uc_op_work[i].msg = NULL;
5769 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005770 }
5771
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305772 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005773 hdd_ctx->hdd_ipa = NULL;
5774
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305775 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005776}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005777
5778/**
Govind Singh1dab23b2017-08-12 13:31:00 +05305779 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_flush
5780 * @hdd_ctx: HDD global context
5781 *
5782 * Return: None
5783 */
5784void hdd_ipa_flush(struct hdd_context *hdd_ctx)
5785{
5786 cds_ssr_protect(__func__);
5787 __hdd_ipa_flush(hdd_ctx);
5788 cds_ssr_unprotect(__func__);
5789}
5790
5791/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005792 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5793 * @hdd_ctx: HDD global context
5794 *
5795 * Return: QDF_STATUS enumeration
5796 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005797QDF_STATUS hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005798{
5799 QDF_STATUS ret;
5800
5801 cds_ssr_protect(__func__);
5802 ret = __hdd_ipa_cleanup(hdd_ctx);
5803 cds_ssr_unprotect(__func__);
5804
5805 return ret;
5806}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005807#endif /* IPA_OFFLOAD */