blob: 4cfa13ca8080ec47bca47ea179a27bb9c627c184 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
jge62037862016-12-09 10:44:33 +08002 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ipa.c
30 *
31 * WLAN HDD and ipa interface implementation
32 * Originally written by Qualcomm Atheros, Inc
33 */
34
35#ifdef IPA_OFFLOAD
36
37/* Include Files */
Mohit Khannafa99aea2016-05-12 21:43:13 -070038#include <linux/ipa.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039#include <wlan_hdd_includes.h>
40#include <wlan_hdd_ipa.h>
41
42#include <linux/etherdevice.h>
43#include <linux/atomic.h>
44#include <linux/netdevice.h>
45#include <linux/skbuff.h>
46#include <linux/list.h>
47#include <linux/debugfs.h>
48#include <linux/inetdevice.h>
49#include <linux/ip.h>
50#include <wlan_hdd_softap_tx_rx.h>
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +053051#include <ol_txrx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070052#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053
54#include "cds_sched.h"
55
56#include "wma.h"
57#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080058#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
Dhanashri Atreb08959a2016-03-01 17:28:03 -080060#include "cdp_txrx_ipa.h"
61
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080062#define HDD_IPA_DESC_BUFFER_RATIO 4
63#define HDD_IPA_IPV4_NAME_EXT "_ipv4"
64#define HDD_IPA_IPV6_NAME_EXT "_ipv6"
65
66#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
68/* WDI TX and RX PIPE */
69#define HDD_IPA_UC_NUM_WDI_PIPE 2
70#define HDD_IPA_UC_MAX_PENDING_EVENT 33
71
72#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
73#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
74#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
75#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
76
77#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
78#define HDD_IPA_MAX_IFACE 3
79#define HDD_IPA_MAX_SYSBAM_PIPE 4
80#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
81#define HDD_IPA_ENABLE_MASK BIT(0)
82#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
83#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
84#define HDD_IPA_RM_ENABLE_MASK BIT(3)
85#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
86#define HDD_IPA_UC_ENABLE_MASK BIT(5)
87#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
88#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
89
Yun Parkf19e07d2015-11-20 11:34:27 -080090#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
91
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080092typedef enum {
93 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,
98 /* keep this last */
99 HDD_IPA_UC_OPCODE_MAX
100} hdd_ipa_uc_op_code;
101
102/**
103 * enum - Reason codes for stat query
104 *
105 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
106 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
107 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800108 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800109 */
110enum {
111 HDD_IPA_UC_STAT_REASON_NONE,
112 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -0800113 HDD_IPA_UC_STAT_REASON_BW_CAL,
114 HDD_IPA_UC_STAT_REASON_DUMP_INFO
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800115};
116
117/**
118 * enum hdd_ipa_rm_state - IPA resource manager state
119 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
120 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
121 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
122 */
123enum hdd_ipa_rm_state {
124 HDD_IPA_RM_RELEASED,
125 HDD_IPA_RM_GRANT_PENDING,
126 HDD_IPA_RM_GRANTED,
127};
128
129struct llc_snap_hdr {
130 uint8_t dsap;
131 uint8_t ssap;
132 uint8_t resv[4];
133 __be16 eth_type;
134} __packed;
135
Leo Chang3bc8fed2015-11-13 10:59:47 -0800136/**
137 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
138 * @eth: ether II header
139 * @llc_snap: LLC snap header
140 *
141 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800142struct hdd_ipa_tx_hdr {
143 struct ethhdr eth;
144 struct llc_snap_hdr llc_snap;
145} __packed;
146
Leo Chang3bc8fed2015-11-13 10:59:47 -0800147/**
148 * struct frag_header - fragment header type registered to IPA hardware
149 * @length: fragment length
150 * @reserved1: Reserved not used
151 * @reserved2: Reserved not used
152 *
153 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800154struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800155 uint16_t length;
156 uint32_t reserved1;
157 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800158} __packed;
159
Leo Chang3bc8fed2015-11-13 10:59:47 -0800160/**
161 * struct ipa_header - ipa header type registered to IPA hardware
162 * @vdev_id: vdev id
163 * @reserved: Reserved not used
164 *
165 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800166struct ipa_header {
167 uint32_t
168 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
169 reserved:24;
170} __packed;
171
Leo Chang3bc8fed2015-11-13 10:59:47 -0800172/**
173 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
174 * @frag_hd: fragment header
175 * @ipa_hd: ipa header
176 * @eth: ether II header
177 *
178 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800179struct hdd_ipa_uc_tx_hdr {
180 struct frag_header frag_hd;
181 struct ipa_header ipa_hd;
182 struct ethhdr eth;
183} __packed;
184
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185/**
186 * struct hdd_ipa_cld_hdr - IPA CLD Header
187 * @reserved: reserved fields
188 * @iface_id: interface ID
189 * @sta_id: Station ID
190 *
191 * Packed 32-bit structure
192 * +----------+----------+--------------+--------+
193 * | Reserved | QCMAP ID | interface id | STA ID |
194 * +----------+----------+--------------+--------+
195 */
196struct hdd_ipa_cld_hdr {
197 uint8_t reserved[2];
198 uint8_t iface_id;
199 uint8_t sta_id;
200} __packed;
201
202struct hdd_ipa_rx_hdr {
203 struct hdd_ipa_cld_hdr cld_hdr;
204 struct ethhdr eth;
205} __packed;
206
207struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700208 bool exception;
209 hdd_adapter_t *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800210 struct hdd_ipa_iface_context *iface_context;
211 struct ipa_rx_data *ipa_tx_desc;
212};
213
214struct hdd_ipa_uc_rx_hdr {
215 struct ethhdr eth;
216} __packed;
217
218struct hdd_ipa_sys_pipe {
219 uint32_t conn_hdl;
220 uint8_t conn_hdl_valid;
221 struct ipa_sys_connect_params ipa_sys_params;
222};
223
224struct hdd_ipa_iface_stats {
225 uint64_t num_tx;
226 uint64_t num_tx_drop;
227 uint64_t num_tx_err;
228 uint64_t num_tx_cac_drop;
229 uint64_t num_rx_prefilter;
230 uint64_t num_rx_ipa_excep;
231 uint64_t num_rx_recv;
232 uint64_t num_rx_recv_mul;
233 uint64_t num_rx_send_desc_err;
234 uint64_t max_rx_mul;
235};
236
237struct hdd_ipa_priv;
238
239struct hdd_ipa_iface_context {
240 struct hdd_ipa_priv *hdd_ipa;
241 hdd_adapter_t *adapter;
242 void *tl_context;
243
244 enum ipa_client_type cons_client;
245 enum ipa_client_type prod_client;
246
247 uint8_t iface_id; /* This iface ID */
248 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530249 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800250 uint32_t ifa_address;
251 struct hdd_ipa_iface_stats stats;
252};
253
254struct hdd_ipa_stats {
255 uint32_t event[IPA_WLAN_EVENT_MAX];
256 uint64_t num_send_msg;
257 uint64_t num_free_msg;
258
259 uint64_t num_rm_grant;
260 uint64_t num_rm_release;
261 uint64_t num_rm_grant_imm;
262 uint64_t num_cons_perf_req;
263 uint64_t num_prod_perf_req;
264
265 uint64_t num_rx_drop;
266 uint64_t num_rx_ipa_tx_dp;
267 uint64_t num_rx_ipa_splice;
268 uint64_t num_rx_ipa_loop;
269 uint64_t num_rx_ipa_tx_dp_err;
270 uint64_t num_rx_ipa_write_done;
271 uint64_t num_max_ipa_tx_mul;
272 uint64_t num_rx_ipa_hw_maxed_out;
273 uint64_t max_pend_q_cnt;
274
275 uint64_t num_tx_comp_cnt;
276 uint64_t num_tx_queued;
277 uint64_t num_tx_dequeued;
278 uint64_t num_max_pm_queue;
279
280 uint64_t num_freeq_empty;
281 uint64_t num_pri_freeq_empty;
282 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800283 uint64_t num_tx_fwd_ok;
284 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800285};
286
287struct ipa_uc_stas_map {
288 bool is_reserved;
289 uint8_t sta_id;
290};
291struct op_msg_type {
292 uint8_t msg_t;
293 uint8_t rsvd;
294 uint16_t op_code;
295 uint16_t len;
296 uint16_t rsvd_snd;
297};
298
299struct ipa_uc_fw_stats {
300 uint32_t tx_comp_ring_base;
301 uint32_t tx_comp_ring_size;
302 uint32_t tx_comp_ring_dbell_addr;
303 uint32_t tx_comp_ring_dbell_ind_val;
304 uint32_t tx_comp_ring_dbell_cached_val;
305 uint32_t tx_pkts_enqueued;
306 uint32_t tx_pkts_completed;
307 uint32_t tx_is_suspend;
308 uint32_t tx_reserved;
309 uint32_t rx_ind_ring_base;
310 uint32_t rx_ind_ring_size;
311 uint32_t rx_ind_ring_dbell_addr;
312 uint32_t rx_ind_ring_dbell_ind_val;
313 uint32_t rx_ind_ring_dbell_ind_cached_val;
314 uint32_t rx_ind_ring_rdidx_addr;
315 uint32_t rx_ind_ring_rd_idx_cached_val;
316 uint32_t rx_refill_idx;
317 uint32_t rx_num_pkts_indicated;
318 uint32_t rx_buf_refilled;
319 uint32_t rx_num_ind_drop_no_space;
320 uint32_t rx_num_ind_drop_no_buf;
321 uint32_t rx_is_suspend;
322 uint32_t rx_reserved;
323};
324
325struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530326 qdf_list_node_t node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800327 hdd_adapter_t *adapter;
328 enum ipa_wlan_event type;
329 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530330 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800331};
332
333/**
334 * struct uc_rm_work_struct
335 * @work: uC RM work
336 * @event: IPA RM event
337 */
338struct uc_rm_work_struct {
339 struct work_struct work;
340 enum ipa_rm_event event;
341};
342
343/**
344 * struct uc_op_work_struct
345 * @work: uC OP work
346 * @msg: OP message
347 */
348struct uc_op_work_struct {
349 struct work_struct work;
350 struct op_msg_type *msg;
351};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800352
353/**
354 * struct uc_rt_debug_info
355 * @time: system time
356 * @ipa_excep_count: IPA exception packet count
357 * @rx_drop_count: IPA Rx drop packet count
358 * @net_sent_count: IPA Rx packet sent to network stack count
359 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800360 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800361 * @tx_fwd_count: IPA Tx forward packet count
362 * @rx_destructor_call: IPA Rx packet destructor count
363 */
364struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530365 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800366 uint64_t ipa_excep_count;
367 uint64_t rx_drop_count;
368 uint64_t net_sent_count;
369 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800370 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800371 uint64_t tx_fwd_count;
372 uint64_t rx_destructor_call;
373};
374
375struct hdd_ipa_priv {
376 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
377 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
378 uint8_t num_iface;
379 enum hdd_ipa_rm_state rm_state;
380 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530381 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800382 * APIs as it is taken care gracefully. Without this, kernel would throw
383 * an warning if spin_lock_bh is used while IRQ is disabled
384 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530385 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800386 struct uc_rm_work_struct uc_rm_work;
387 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530388 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800389 struct delayed_work wake_lock_work;
390 bool wake_lock_released;
391
392 enum ipa_client_type prod_client;
393
394 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530395 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800396 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530397 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800398 bool suspended;
399
400 uint32_t pending_hw_desc_cnt;
401 uint32_t hw_desc_cnt;
402 spinlock_t q_lock;
403 uint32_t freeq_cnt;
404 struct list_head free_desc_head;
405
406 uint32_t pend_q_cnt;
407 struct list_head pend_desc_head;
408
409 hdd_context_t *hdd_ctx;
410
411 struct dentry *debugfs_dir;
412 struct hdd_ipa_stats stats;
413
414 struct notifier_block ipv4_notifier;
415 uint32_t curr_prod_bw;
416 uint32_t curr_cons_bw;
417
418 uint8_t activated_fw_pipe;
419 uint8_t sap_num_connected_sta;
420 uint8_t sta_connected;
421 uint32_t tx_pipe_handle;
422 uint32_t rx_pipe_handle;
423 bool resource_loading;
424 bool resource_unloading;
425 bool pending_cons_req;
426 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530427 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530428 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700429 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800430 uint32_t ipa_tx_packets_diff;
431 uint32_t ipa_rx_packets_diff;
432 uint32_t ipa_p_tx_packets;
433 uint32_t ipa_p_rx_packets;
434 uint32_t stat_req_reason;
435 uint64_t ipa_tx_forward;
436 uint64_t ipa_rx_discard;
437 uint64_t ipa_rx_net_send_count;
438 uint64_t ipa_rx_internel_drop_count;
439 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530440 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800441 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
442 unsigned int rt_buf_fill_index;
Anurag Chouhan210db072016-02-22 18:42:15 +0530443 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530444 qdf_mutex_t rt_debug_lock;
445 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800446 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800447 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530448 qdf_dma_addr_t tx_comp_doorbell_paddr;
449 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800450
451 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
452 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800453};
454
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800455/**
Houston Hoffman23e76f92016-02-26 12:19:11 -0800456 * FIXME: The following conversion routines are just stubs.
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800457 * They will be implemented fully by another update.
458 * The stubs will let the compile go ahead, and functionality
459 * is broken.
460 * This should be OK and IPA is not enabled yet
461 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700462static void *wlan_hdd_stub_priv_to_addr(uint32_t priv)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800463{
464 void *vaddr;
465 uint32_t ipa_priv = priv;
466
467 vaddr = &ipa_priv; /* just to use the var */
468 vaddr = NULL;
469 return vaddr;
470}
471
Jeff Johnsond7720632016-10-05 16:04:32 -0700472static uint32_t wlan_hdd_stub_addr_to_priv(void *ptr)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800473{
474 uint32_t ipa_priv = 0;
475
476 BUG_ON(ptr == NULL);
477 return ipa_priv;
478}
Leo Changcc923e22016-06-16 15:29:03 -0700479
480#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
481#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800482#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
483#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
484#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
485#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
486#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
487#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700488#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
489 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800490
491#define HDD_IPA_GET_IFACE_ID(_data) \
492 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
493
494#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530495 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800496 "%s:%d: "fmt, __func__, __LINE__, ## args)
497
Govind Singhb6a89772016-08-12 11:23:35 +0530498#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
499 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
500 "%s:%d: "fmt, __func__, __LINE__, ## args)
501
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800502#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
503 do { \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530504 QDF_TRACE(QDF_MODULE_ID_HDD, _lvl, "%s:", _prefix); \
505 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800506 } while (0)
507
508#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
509 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
510
511#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
512 do { \
513 hdd_ipa->ipa_rx_internel_drop_count++; \
514 } while (0)
515#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
516 do { \
517 hdd_ipa->ipa_rx_net_send_count++; \
518 } while (0)
519#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
520
Leo Chang07b28f62016-05-11 12:29:22 -0700521#if defined (QCA_WIFI_3_0) && defined (CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800522#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
523do { \
524 pipe_in.u.ul.rdy_ring_rp_va = \
525 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
526 pipe_in.u.ul.rdy_comp_ring_base_pa = \
527 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
528 pipe_in.u.ul.rdy_comp_ring_size = \
529 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
530 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
531 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
532 pipe_in.u.ul.rdy_comp_ring_wp_va = \
533 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800534} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700535
536#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800537#else
538/* Do nothing */
539#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
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
559/* For Tx pipes, use Ethernet-II Header format */
560struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
561 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800562 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800563 0x00000000,
564 0x00000000
565 },
566 {
567 0x00000000
568 },
569 {
570 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
571 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
572 0x0008
573 }
574};
575
576/* For Tx pipes, use 802.3 Header format */
577static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
578 {
579 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
580 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
581 0x00 /* length can be zero */
582 },
583 {
584 /* LLC SNAP header 8 bytes */
585 0xaa, 0xaa,
586 {0x03, 0x00, 0x00, 0x00},
587 0x0008 /* type value(2 bytes) ,filled by wlan */
588 /* 0x0800 - IPV4, 0x86dd - IPV6 */
589 }
590};
591
592static const char *op_string[] = {
593 "TX_SUSPEND",
594 "TX_RESUME",
595 "RX_SUSPEND",
596 "RX_RESUME",
597 "STATS",
598};
599
600static struct hdd_ipa_priv *ghdd_ipa;
601
602/* Local Function Prototypes */
603static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
604 unsigned long data);
605static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
606 unsigned long data);
607
608static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Mohit Khannafa99aea2016-05-12 21:43:13 -0700609static void hdd_ipa_uc_proc_pending_event (struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800610
611/**
612 * hdd_ipa_is_enabled() - Is IPA enabled?
613 * @hdd_ctx: Global HDD context
614 *
615 * Return: true if IPA is enabled, false otherwise
616 */
617bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
618{
619 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
620}
621
622/**
623 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
624 * @hdd_ctx: Global HDD context
625 *
626 * Return: true if IPA uC offload is enabled, false otherwise
627 */
628bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
629{
630 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
631}
632
633/**
634 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
635 * @hdd_ctx: Global HDD context
636 *
637 * Return: true if STA mode IPA uC offload is enabled, false otherwise
638 */
639static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
640{
641 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
642}
643
644/**
Guolei Bianca144d82016-11-10 11:07:42 +0800645 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
646 * @hdd_ipa: Global HDD IPA context
647 *
648 * Return: None
649 */
650#ifdef IPA_UC_STA_OFFLOAD
651static inline void hdd_ipa_uc_sta_reset_sta_connected(
652 struct hdd_ipa_priv *hdd_ipa)
653{
654 vos_lock_acquire(&hdd_ipa->event_lock);
655 hdd_ipa->sta_connected = 0;
656 vos_lock_release(&hdd_ipa->event_lock);
657}
658#else
659static inline void hdd_ipa_uc_sta_reset_sta_connected(
660 struct hdd_ipa_priv *hdd_ipa)
661{
662}
663#endif
664
665/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800666 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
667 * @hdd_ipa: Global HDD IPA context
668 *
669 * Return: true if pre-filter is enabled, otherwise false
670 */
671static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
672{
673 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
674 HDD_IPA_PRE_FILTER_ENABLE_MASK);
675}
676
677/**
678 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
679 * @hdd_ipa: Global HDD IPA context
680 *
681 * Return: true if IPv6 is enabled, otherwise false
682 */
683static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
684{
685 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
686}
687
688/**
689 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
690 * @hdd_ipa: Global HDD IPA context
691 *
692 * Return: true if resource manager is enabled, otherwise false
693 */
694static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
695{
696 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
697}
698
699/**
700 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
701 * @hdd_ipa: Global HDD IPA context
702 *
703 * Return: true if resource manager is enabled, otherwise false
704 */
705static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
706{
707 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
708}
709
710/**
711 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
712 * @hdd_ipa: Global HDD IPA context
713 *
714 * Return: true if clock scaling is enabled, otherwise false
715 */
716static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
717{
718 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
719 HDD_IPA_CLK_SCALING_ENABLE_MASK |
720 HDD_IPA_RM_ENABLE_MASK);
721}
722
723/**
724 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
725 * @ctext: pointer to hdd context.
726 *
727 * If rt debug enabled, periodically called, and fill debug buffer
728 *
729 * Return: none
730 */
731static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
732{
733 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
734 struct hdd_ipa_priv *hdd_ipa;
735 struct uc_rt_debug_info *dump_info = NULL;
736
737 if (wlan_hdd_validate_context(hdd_ctx))
738 return;
739
740 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530741 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742 "%s: IPA UC is not enabled", __func__);
743 return;
744 }
745
746 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
747
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530748 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800749 dump_info = &hdd_ipa->rt_bug_buffer[
750 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
751
Deepthi Gowri6acee342016-10-28 15:00:38 +0530752 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800753 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
754 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
755 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800756 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800757 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
758 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800759 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
760 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530761 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800762
Anurag Chouhan210db072016-02-22 18:42:15 +0530763 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800764 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
765}
766
767/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700768 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800769 * @hdd_ctx: pointer to hdd context.
770 *
771 * If rt debug enabled, dump debug buffer contents based on requirement
772 *
773 * Return: none
774 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700775static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800776{
777 struct hdd_ipa_priv *hdd_ipa;
778 unsigned int dump_count;
779 unsigned int dump_index;
780 struct uc_rt_debug_info *dump_info = NULL;
781
782 if (wlan_hdd_validate_context(hdd_ctx))
783 return;
784
785 hdd_ipa = hdd_ctx->hdd_ipa;
786 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530787 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800788 "%s: IPA UC is not enabled", __func__);
789 return;
790 }
791
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530792 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530794 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800795 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530797 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800798 for (dump_count = 0;
799 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
800 dump_count++) {
801 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
802 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
803 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530804 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530805 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800806 dump_info->time, dump_info->ipa_excep_count,
807 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800808 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800809 dump_info->rx_destructor_call,
810 dump_info->rx_discard_count);
811 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530812 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530813 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800814 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
815}
816
817/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700818 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
819 * __hdd_ipa_uc_rt_debug_host_dump
820 * @hdd_ctx: pointer to hdd context.
821 *
822 * If rt debug enabled, dump debug buffer contents based on requirement
823 *
824 * Return: none
825 */
826void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
827{
828 cds_ssr_protect(__func__);
829 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
830 cds_ssr_unprotect(__func__);
831}
832
833/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
835 * @ctext: pointer to hdd context.
836 *
837 * periodically called by timer expire
838 * will try to alloc dummy memory and detect out of memory condition
839 * if out of memory detected, dump wlan-ipa stats
840 *
841 * Return: none
842 */
843static void hdd_ipa_uc_rt_debug_handler(void *ctext)
844{
845 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700846 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847 void *dummy_ptr = NULL;
848
849 if (wlan_hdd_validate_context(hdd_ctx))
850 return;
851
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700852 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
853
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -0800855 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800856 return;
857 }
858
859 /* Allocate dummy buffer periodically and free immediately. this will
860 * proactively detect OOM and if allocation fails dump ipa stats
861 */
862 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
863 GFP_KERNEL | GFP_ATOMIC);
864 if (!dummy_ptr) {
Yun Parkb187d542016-11-14 18:10:04 -0800865 hdd_alert("Dummy alloc fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
867 hdd_ipa_uc_stat_request(
Krunal Sonibe766b02016-03-10 13:00:44 -0800868 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800869 } else {
870 kfree(dummy_ptr);
871 }
872
Anurag Chouhan210db072016-02-22 18:42:15 +0530873 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800874 HDD_IPA_UC_RT_DEBUG_PERIOD);
875}
876
877/**
Yun Parkb187d542016-11-14 18:10:04 -0800878 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800879 * @skb: packet pinter
880 *
881 * when free data packet, will be invoked by wlan client and will increase
882 * free counter
883 *
884 * Return: none
885 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700886static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800887{
888 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530889 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800890 "%s: invalid hdd context", __func__);
891 return;
892 }
893
894 ghdd_ipa->ipa_rx_destructor_count++;
895}
896
897/**
Yun Parkb187d542016-11-14 18:10:04 -0800898 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899 * @hdd_ctx: hdd main context
900 *
901 * free all rt debugging resources
902 *
903 * Return: none
904 */
905static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
906{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700907 struct hdd_ipa_priv *hdd_ipa;
908
909 if (wlan_hdd_validate_context(hdd_ctx))
910 return;
911
912 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800913
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530914 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800915
916 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -0800917 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800918 return;
919 }
920
Anurag Chouhan210db072016-02-22 18:42:15 +0530921 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -0800922 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
923 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
924 }
925 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
926
927 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +0530928 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
929 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800930 }
Anurag Chouhan210db072016-02-22 18:42:15 +0530931 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800932}
933
934/**
Yun Parkb187d542016-11-14 18:10:04 -0800935 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800936 * @hdd_ctx: hdd main context
937 *
938 * alloc and initialize all rt debugging resources
939 *
940 * Return: none
941 */
942static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
943{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700944 struct hdd_ipa_priv *hdd_ipa;
945
946 if (wlan_hdd_validate_context(hdd_ctx))
947 return;
948
949 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800950
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530951 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800952 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530953 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800954 sizeof(struct uc_rt_debug_info) *
955 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
956 hdd_ipa->ipa_tx_forward = 0;
957 hdd_ipa->ipa_rx_discard = 0;
958 hdd_ipa->ipa_rx_net_send_count = 0;
959 hdd_ipa->ipa_rx_internel_drop_count = 0;
960 hdd_ipa->ipa_rx_destructor_count = 0;
961
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962 /* Reatime debug enable on feature enable */
963 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -0800964 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800965 return;
966 }
Yun Parkdfc1da52016-11-15 14:50:11 -0800967
968 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
969 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
970 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
971 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
972
Anurag Chouhan210db072016-02-22 18:42:15 +0530973 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800974 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +0530975 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800976 HDD_IPA_UC_RT_DEBUG_PERIOD);
977
978}
979
980/**
Yun Parkb187d542016-11-14 18:10:04 -0800981 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
982 * @hdd_ipa: HDD IPA struct
983 *
984 * Dump entries in struct hdd_ipa
985 *
986 * Return: none
987 */
988static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
989{
990 int i;
991
992 /* HDD IPA */
993 hdd_err("==== HDD IPA ====\n"
994 "num_iface: %d\n"
995 "rm_state: %d\n"
996 "rm_lock: %p\n"
997 "uc_rm_work: %p\n"
998 "uc_op_work: %p\n"
999 "wake_lock: %p\n"
1000 "wake_lock_work: %p\n"
1001 "wake_lock_released: %d\n"
1002 "prod_client: %d\n"
1003 "tx_ref_cnt: %d\n"
1004 "pm_queue_head----\n"
1005 "\thead: %p\n"
1006 "\ttail: %p\n"
1007 "\tqlen: %d\n"
1008 "pm_work: %p\n"
1009 "pm_lock: %p\n"
1010 "suspended: %d\n",
1011 hdd_ipa->num_iface,
1012 hdd_ipa->rm_state,
1013 &hdd_ipa->rm_lock,
1014 &hdd_ipa->uc_rm_work,
1015 &hdd_ipa->uc_op_work,
1016 &hdd_ipa->wake_lock,
1017 &hdd_ipa->wake_lock_work,
1018 hdd_ipa->wake_lock_released,
1019 hdd_ipa->prod_client,
1020 hdd_ipa->tx_ref_cnt.counter,
1021 hdd_ipa->pm_queue_head.head,
1022 hdd_ipa->pm_queue_head.tail,
1023 hdd_ipa->pm_queue_head.qlen,
1024 &hdd_ipa->pm_work,
1025 &hdd_ipa->pm_lock,
1026 hdd_ipa->suspended);
1027 hdd_err("\npending_hw_desc_cnt: %d\n"
1028 "hw_desc_cnt: %d\n"
1029 "q_lock: %p\n"
1030 "freeq_cnt: %d\n"
1031 "free_desc_head----\n"
1032 "\tnext: %p\n"
1033 "\tprev: %p\n"
1034 "pend_q_cnt: %d\n"
1035 "pend_desc_head----\n"
1036 "\tnext: %p\n"
1037 "\tprev: %p\n"
1038 "hdd_ctx: %p\n"
1039 "debugfs_dir: %p\n"
1040 "stats: %p\n"
1041 "ipv4_notifier: %p\n"
1042 "curr_prod_bw: %d\n"
1043 "curr_cons_bw: %d\n"
1044 "activated_fw_pipe: %d\n"
1045 "sap_num_connected_sta: %d\n"
1046 "sta_connected: %d\n",
1047 hdd_ipa->pending_hw_desc_cnt,
1048 hdd_ipa->hw_desc_cnt,
1049 &hdd_ipa->q_lock,
1050 hdd_ipa->freeq_cnt,
1051 hdd_ipa->free_desc_head.next,
1052 hdd_ipa->free_desc_head.prev,
1053 hdd_ipa->pend_q_cnt,
1054 hdd_ipa->pend_desc_head.next,
1055 hdd_ipa->pend_desc_head.prev,
1056 hdd_ipa->hdd_ctx,
1057 hdd_ipa->debugfs_dir,
1058 &hdd_ipa->stats,
1059 &hdd_ipa->ipv4_notifier,
1060 hdd_ipa->curr_prod_bw,
1061 hdd_ipa->curr_cons_bw,
1062 hdd_ipa->activated_fw_pipe,
1063 hdd_ipa->sap_num_connected_sta,
1064 (unsigned int)hdd_ipa->sta_connected
1065 );
1066 hdd_err("\ntx_pipe_handle: 0x%x\n"
1067 "rx_pipe_handle: 0x%x\n"
1068 "resource_loading: %d\n"
1069 "resource_unloading: %d\n"
1070 "pending_cons_req: %d\n"
1071 "pending_event----\n"
1072 "\tanchor.next: %p\n"
1073 "\tanchor.prev: %p\n"
1074 "\tcount: %d\n"
1075 "\tmax_size: %d\n"
1076 "event_lock: %p\n"
1077 "ipa_tx_packets_diff: %d\n"
1078 "ipa_rx_packets_diff: %d\n"
1079 "ipa_p_tx_packets: %d\n"
1080 "ipa_p_rx_packets: %d\n"
1081 "stat_req_reason: %d\n",
1082 hdd_ipa->tx_pipe_handle,
1083 hdd_ipa->rx_pipe_handle,
1084 hdd_ipa->resource_loading,
1085 hdd_ipa->resource_unloading,
1086 hdd_ipa->pending_cons_req,
1087 hdd_ipa->pending_event.anchor.next,
1088 hdd_ipa->pending_event.anchor.prev,
1089 hdd_ipa->pending_event.count,
1090 hdd_ipa->pending_event.max_size,
1091 &hdd_ipa->event_lock,
1092 hdd_ipa->ipa_tx_packets_diff,
1093 hdd_ipa->ipa_rx_packets_diff,
1094 hdd_ipa->ipa_p_tx_packets,
1095 hdd_ipa->ipa_p_rx_packets,
1096 hdd_ipa->stat_req_reason);
1097
1098 hdd_err("assoc_stas_map([id]is_reserved/sta_id): ");
1099 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
1100 hdd_err(" [%d]%d/%d", i,
1101 hdd_ipa->assoc_stas_map[i].is_reserved,
1102 hdd_ipa->assoc_stas_map[i].sta_id);
1103 }
1104}
1105
1106/**
1107 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1108 * @hdd_ipa: HDD IPA struct
1109 *
1110 * Dump entire struct hdd_ipa_sys_pipe
1111 *
1112 * Return: none
1113 */
1114static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1115{
1116 int i;
1117
1118 /* IPA SYS Pipes */
1119 hdd_err("==== IPA SYS Pipes ====\n");
1120
1121 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1122 struct hdd_ipa_sys_pipe *sys_pipe;
1123 struct ipa_sys_connect_params *ipa_sys_params;
1124
1125 sys_pipe = &hdd_ipa->sys_pipe[i];
1126 ipa_sys_params = &sys_pipe->ipa_sys_params;
1127
1128 hdd_err("sys_pipe[%d]----\n"
1129 "\tconn_hdl: 0x%x\n"
1130 "\tconn_hdl_valid: %d\n"
1131 "\tnat_en: %d\n"
1132 "\thdr_len %d\n"
1133 "\thdr_additional_const_len: %d\n"
1134 "\thdr_ofst_pkt_size_valid: %d\n"
1135 "\thdr_ofst_pkt_size: %d\n"
1136 "\thdr_little_endian: %d\n"
1137 "\tmode: %d\n"
1138 "\tclient: %d\n"
1139 "\tdesc_fifo_sz: %d\n"
1140 "\tpriv: %p\n"
1141 "\tnotify: %p\n"
1142 "\tskip_ep_cfg: %d\n"
1143 "\tkeep_ipa_awake: %d\n",
1144 i,
1145 sys_pipe->conn_hdl,
1146 sys_pipe->conn_hdl_valid,
1147 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1148 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1149 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1150 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1151 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1152 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1153 ipa_sys_params->ipa_ep_cfg.mode.mode,
1154 ipa_sys_params->client,
1155 ipa_sys_params->desc_fifo_sz,
1156 ipa_sys_params->priv,
1157 ipa_sys_params->notify,
1158 ipa_sys_params->skip_ep_cfg,
1159 ipa_sys_params->keep_ipa_awake);
1160 }
1161}
1162
1163/**
1164 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1165 * @hdd_ipa: HDD IPA struct
1166 *
1167 * Dump entire struct hdd_ipa_iface_context
1168 *
1169 * Return: none
1170 */
1171static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1172{
1173 int i;
1174
1175 /* IPA Interface Contexts */
1176 hdd_err("==== IPA Interface Contexts ====\n");
1177
1178 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1179 struct hdd_ipa_iface_context *iface_context;
1180
1181 iface_context = &hdd_ipa->iface_context[i];
1182
1183 hdd_err("iface_context[%d]----\n"
1184 "\thdd_ipa: %p\n"
1185 "\tadapter: %p\n"
1186 "\ttl_context: %p\n"
1187 "\tcons_client: %d\n"
1188 "\tprod_client: %d\n"
1189 "\tiface_id: %d\n"
1190 "\tsta_id: %d\n"
1191 "\tinterface_lock: %p\n"
1192 "\tifa_address: 0x%x\n",
1193 i,
1194 iface_context->hdd_ipa,
1195 iface_context->adapter,
1196 iface_context->tl_context,
1197 iface_context->cons_client,
1198 iface_context->prod_client,
1199 iface_context->iface_id,
1200 iface_context->sta_id,
1201 &iface_context->interface_lock,
1202 iface_context->ifa_address);
1203 }
1204}
1205
1206/**
1207 * hdd_ipa_dump_info() - dump HDD IPA struct
1208 * @pHddCtx: hdd main context
1209 *
1210 * Dump entire struct hdd_ipa
1211 *
1212 * Return: none
1213 */
1214void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1215{
1216 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1217
1218 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1219 hdd_ipa_dump_sys_pipe(hdd_ipa);
1220 hdd_ipa_dump_iface_context(hdd_ipa);
1221}
1222
1223/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001224 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001225 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001226 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1227 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001228 *
1229 * Return: true if IPA is enabled, false otherwise
1230 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001231static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1233{
1234 struct hdd_ipa_priv *hdd_ipa;
1235
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 *ipa_tx_diff = 0;
1237 *ipa_rx_diff = 0;
1238
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001239 if (wlan_hdd_validate_context(hdd_ctx))
1240 return;
1241
1242 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1243
1244 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1245 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001246 return;
1247 }
1248
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301249 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001250 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1251 (false == hdd_ipa->resource_loading)) {
1252 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1253 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001254 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001255 *ipa_tx_diff, *ipa_rx_diff);
1256 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301257 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001258 return;
1259}
1260
1261/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001262 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1263 * @hdd_ctx: Global HDD context
1264 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1265 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1266 *
1267 * Return: true if IPA is enabled, false otherwise
1268 */
1269void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1270 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1271{
1272 cds_ssr_protect(__func__);
1273 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1274 cds_ssr_unprotect(__func__);
1275}
1276
1277/**
1278 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 * @adapter: network adapter
1280 * @reason: STAT REQ Reason
1281 *
1282 * Return: None
1283 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001284static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001285{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001286 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001287 struct hdd_ipa_priv *hdd_ipa;
1288
1289 if (!adapter) {
1290 return;
1291 }
1292
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001293 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1294
1295 if (wlan_hdd_validate_context(hdd_ctx))
1296 return;
1297
1298 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1299 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1300 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001301 return;
1302 }
1303
Yun Parkb187d542016-11-14 18:10:04 -08001304 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301305 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001306 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1307 (false == hdd_ipa->resource_loading)) {
1308 hdd_ipa->stat_req_reason = reason;
1309 wma_cli_set_command(
1310 (int)adapter->sessionId,
1311 (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
1312 0, VDEV_CMD);
1313 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301314 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001315}
1316
1317/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001318 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1319 * @adapter: network adapter
1320 * @reason: STAT REQ Reason
1321 *
1322 * Return: None
1323 */
1324void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1325{
1326 cds_ssr_protect(__func__);
1327 __hdd_ipa_uc_stat_request(adapter, reason);
1328 cds_ssr_unprotect(__func__);
1329}
1330
1331/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001332 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1333 * @hdd_ipa: Global HDD IPA context
1334 * @sta_add: Should station be added
1335 * @sta_id: ID of the station being queried
1336 *
1337 * Return: true if the station was found
1338 */
1339static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1340 bool sta_add, uint8_t sta_id)
1341{
1342 bool sta_found = false;
1343 uint8_t idx;
1344 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1345 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1346 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1347 sta_found = true;
1348 break;
1349 }
1350 }
1351 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301352 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001353 "%s: STA ID %d already exist, cannot add",
1354 __func__, sta_id);
1355 return sta_found;
1356 }
1357 if (sta_add) {
1358 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1359 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1360 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1361 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1362 return sta_found;
1363 }
1364 }
1365 }
1366 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301367 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001368 "%s: STA ID %d does not exist, cannot delete",
1369 __func__, sta_id);
1370 return sta_found;
1371 }
1372 if (!sta_add) {
1373 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1374 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1375 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1376 hdd_ipa->assoc_stas_map[idx].is_reserved =
1377 false;
1378 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1379 return sta_found;
1380 }
1381 }
1382 }
1383 return sta_found;
1384}
1385
1386/**
1387 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1388 * @hdd_ipa: Global HDD IPA context
1389 *
1390 * Return: 0 on success, negative errno if error
1391 */
1392static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1393{
1394 int result;
1395 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001396 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001397
1398 /* ACTIVATE TX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301399 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001400 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1401 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001402 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1403 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301404 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405 "%s: Enable TX PIPE fail, code %d",
1406 __func__, result);
1407 return result;
1408 }
1409 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1410 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301411 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001412 "%s: Resume TX PIPE fail, code %d",
1413 __func__, result);
1414 return result;
1415 }
Leo Changfdb45c32016-10-28 11:09:23 -07001416 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001417
1418 /* ACTIVATE RX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301419 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001420 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1421 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001422 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1423 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301424 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001425 "%s: Enable RX PIPE fail, code %d",
1426 __func__, result);
1427 return result;
1428 }
1429 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1430 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301431 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001432 "%s: Resume RX PIPE fail, code %d",
1433 __func__, result);
1434 return result;
1435 }
Leo Changfdb45c32016-10-28 11:09:23 -07001436 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, true, false);
Leo Change3e49442015-10-26 20:07:13 -07001437 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438 return 0;
1439}
1440
1441/**
1442 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1443 * @hdd_ipa: Global HDD IPA context
1444 *
1445 * Return: 0 on success, negative errno if error
1446 */
1447static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1448{
1449 int result;
1450
Leo Change3e49442015-10-26 20:07:13 -07001451 hdd_ipa->ipa_pipes_down = true;
1452
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301453 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001454 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
1455 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301456 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001457 "%s: Suspend RX PIPE fail, code %d",
1458 __func__, result);
1459 return result;
1460 }
1461 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1462 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301463 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 "%s: Disable RX PIPE fail, code %d",
1465 __func__, result);
1466 return result;
1467 }
1468
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301469 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001470 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
1471 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301472 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001473 "%s: Suspend TX PIPE fail, code %d",
1474 __func__, result);
1475 return result;
1476 }
1477 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1478 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301479 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001480 "%s: Disable TX PIPE fail, code %d",
1481 __func__, result);
1482 return result;
1483 }
1484
1485 return 0;
1486}
1487
1488/**
1489 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1490 * @hdd_ipa: Global HDD IPA context
1491 *
1492 * Return: 0 on success, negative errno if error
1493 */
1494static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1495{
1496 hdd_ipa->activated_fw_pipe = 0;
1497 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001498
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001499 /* If RM feature enabled
1500 * Request PROD Resource first
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08001501 * PROD resource may return sync or async manners
1502 */
Yun Park4cab6ee2015-10-27 11:43:40 -07001503 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
1504 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1505 /* RM PROD request sync return
1506 * enable pipe immediately
1507 */
1508 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301509 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001510 "%s: IPA WDI Pipe activation failed",
1511 __func__);
1512 hdd_ipa->resource_loading = false;
1513 return -EBUSY;
1514 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001515 }
1516 } else {
1517 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001518 * Just enabled all the PIPEs
1519 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001520 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301521 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001522 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523 __func__);
1524 hdd_ipa->resource_loading = false;
1525 return -EBUSY;
1526 }
1527 hdd_ipa->resource_loading = false;
1528 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001529
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301530 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001531 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001532 return 0;
1533}
1534
1535/**
1536 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1537 * @hdd_ipa: Global HDD IPA context
1538 *
1539 * Return: None
1540 */
1541static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1542{
1543 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001544 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001545
Yun Park7c4f31b2016-11-30 10:09:21 -08001546 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
1547 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
1548 QDF_ASSERT(0);
1549 return;
1550 }
1551
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001552 hdd_ipa->resource_unloading = true;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301553 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW RX PIPE", __func__);
Leo Changfdb45c32016-10-28 11:09:23 -07001554 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, false, false);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301555 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW TX PIPE", __func__);
Leo Changfdb45c32016-10-28 11:09:23 -07001556 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001557}
1558
1559/**
1560 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
1561 * @context: User context registered with TL (the IPA Global context is
1562 * registered
1563 * @rxpkt: Packet containing the notification
1564 * @staid: ID of the station associated with the packet
1565 *
1566 * Return: None
1567 */
1568static void
1569hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
1570{
1571 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301572 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001573
1574 /*
1575 * When SSR is going on or driver is unloading, just return.
1576 */
1577 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301578 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001579 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580
1581 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1582 return;
1583
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301584 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001585 __func__, event);
1586
1587 switch (event) {
1588 case IPA_RM_RESOURCE_GRANTED:
1589 /* Differed RM Granted */
1590 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301591 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001592 if ((false == hdd_ipa->resource_unloading) &&
1593 (!hdd_ipa->activated_fw_pipe)) {
1594 hdd_ipa_uc_enable_pipes(hdd_ipa);
1595 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301596 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001597 break;
1598
1599 case IPA_RM_RESOURCE_RELEASED:
1600 /* Differed RM Released */
1601 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001602 break;
1603
1604 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301605 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001606 "%s, invalid event code %d", __func__, event);
1607 break;
1608 }
1609}
1610
1611/**
1612 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
1613 * @hdd_ipa: Global HDD IPA context
1614 * @event: IPA resource manager event to be deferred
1615 *
1616 * This function is called when a resource manager event is received
1617 * from firmware in interrupt context. This function will defer the
1618 * handling to the OL RX thread
1619 *
1620 * Return: None
1621 */
1622static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
1623{
1624 enum ipa_rm_event event;
1625 struct uc_rm_work_struct *uc_rm_work = container_of(work,
1626 struct uc_rm_work_struct, work);
1627 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
1628 struct hdd_ipa_priv, uc_rm_work);
1629
1630 cds_ssr_protect(__func__);
1631 event = uc_rm_work->event;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301632 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001633 "%s, posted event %d", __func__, event);
1634
1635 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
1636 cds_ssr_unprotect(__func__);
1637
1638 return;
1639}
1640
1641/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001642 * hdd_ipa_uc_op_cb() - IPA uC operation callback
1643 * @op_msg: operation message received from firmware
1644 * @usr_ctxt: user context registered with TL (we register the HDD Global
1645 * context)
1646 *
1647 * Return: None
1648 */
1649static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
1650{
1651 struct op_msg_type *msg = op_msg;
1652 struct ipa_uc_fw_stats *uc_fw_stat;
1653 struct IpaHwStatsWDIInfoData_t ipa_stat;
1654 struct hdd_ipa_priv *hdd_ipa;
1655 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301656 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001657
1658 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301659 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001660 return;
1661 }
1662
1663 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301664 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001665 "%s, INVALID OPCODE %d", __func__, msg->op_code);
1666 return;
1667 }
1668
1669 hdd_ctx = (hdd_context_t *) usr_ctxt;
1670
1671 /*
1672 * When SSR is going on or driver is unloading, just return.
1673 */
1674 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301675 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301676 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001677 return;
1678 }
1679
1680 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1681
Govind Singhb6a89772016-08-12 11:23:35 +05301682 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001683 "%s, OPCODE %s", __func__, op_string[msg->op_code]);
1684
1685 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
1686 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301687 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 hdd_ipa->activated_fw_pipe++;
1689 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
1690 hdd_ipa->resource_loading = false;
1691 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08001692 if (hdd_ipa->pending_cons_req)
1693 ipa_rm_notify_completion(
1694 IPA_RM_RESOURCE_GRANTED,
1695 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08001696 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301698 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001699 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301701 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702 hdd_ipa->activated_fw_pipe--;
1703 if (!hdd_ipa->activated_fw_pipe) {
1704 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08001705 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1706 ipa_rm_release_resource(
1707 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08001708 /*
1709 * Sync return success from IPA
1710 * Enable/resume all the PIPEs
1711 */
Yun Park5b635012015-12-02 15:05:01 -08001712 hdd_ipa->resource_unloading = false;
1713 hdd_ipa_uc_proc_pending_event(hdd_ipa);
1714 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001715 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301716 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001717 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001719 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301721 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001723 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001724 "CE RING SIZE: %d\n"
1725 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001726 (unsigned long long)res->ce_sr_base_paddr,
1727 res->ce_sr_ring_size,
1728 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301729 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001731 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732 "COMP RING SIZE: %d\n"
1733 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001734 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001735 (unsigned long long)res->tx_comp_ring_base_paddr,
1736 res->tx_comp_ring_size,
1737 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001738 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301739 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001741 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001743 "IND RING DBELL : 0x%llx\n"
1744 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001745 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08001746 "NUM TX FWD OK : %llu\n"
1747 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08001748 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001749 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08001750 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
1751 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08001753 hdd_ipa->stats.num_tx_fwd_ok,
1754 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301755 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001756 "==== IPA_UC WLAN_HOST CONTROL ====\n"
1757 "SAP NUM STAs: %d\n"
1758 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001759 "CONCURRENT MODE: %s\n"
1760 "TX PIPE HDL: 0x%x\n"
1761 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762 "RSC LOADING : %d\n"
1763 "RSC UNLOADING : %d\n"
1764 "PNDNG CNS RQT : %d",
1765 hdd_ipa->sap_num_connected_sta,
1766 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08001767 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001768 hdd_ipa->tx_pipe_handle,
1769 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08001770 hdd_ipa->resource_loading,
1771 hdd_ipa->resource_unloading,
1772 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001773
1774 /* STATs from FW */
1775 uc_fw_stat = (struct ipa_uc_fw_stats *)
1776 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301777 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001778 "==== IPA_UC WLAN_FW TX ====\n"
1779 "COMP RING BASE: 0x%x\n"
1780 "COMP RING SIZE: %d\n"
1781 "COMP RING DBELL : 0x%x\n"
1782 "COMP RING DBELL IND VAL : %d\n"
1783 "COMP RING DBELL CACHED VAL : %d\n"
1784 "COMP RING DBELL CACHED VAL : %d\n"
1785 "PKTS ENQ : %d\n"
1786 "PKTS COMP : %d\n"
1787 "IS SUSPEND : %d\n"
1788 "RSVD : 0x%x",
1789 uc_fw_stat->tx_comp_ring_base,
1790 uc_fw_stat->tx_comp_ring_size,
1791 uc_fw_stat->tx_comp_ring_dbell_addr,
1792 uc_fw_stat->tx_comp_ring_dbell_ind_val,
1793 uc_fw_stat->tx_comp_ring_dbell_cached_val,
1794 uc_fw_stat->tx_comp_ring_dbell_cached_val,
1795 uc_fw_stat->tx_pkts_enqueued,
1796 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08001797 uc_fw_stat->tx_is_suspend,
1798 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301799 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001800 "==== IPA_UC WLAN_FW RX ====\n"
1801 "IND RING BASE: 0x%x\n"
1802 "IND RING SIZE: %d\n"
1803 "IND RING DBELL : 0x%x\n"
1804 "IND RING DBELL IND VAL : %d\n"
1805 "IND RING DBELL CACHED VAL : %d\n"
1806 "RDY IND ADDR : 0x%x\n"
1807 "RDY IND CACHE VAL : %d\n"
1808 "RFIL IND : %d\n"
1809 "NUM PKT INDICAT : %d\n"
1810 "BUF REFIL : %d\n"
1811 "NUM DROP NO SPC : %d\n"
1812 "NUM DROP NO BUF : %d\n"
1813 "IS SUSPND : %d\n"
1814 "RSVD : 0x%x\n",
1815 uc_fw_stat->rx_ind_ring_base,
1816 uc_fw_stat->rx_ind_ring_size,
1817 uc_fw_stat->rx_ind_ring_dbell_addr,
1818 uc_fw_stat->rx_ind_ring_dbell_ind_val,
1819 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
1820 uc_fw_stat->rx_ind_ring_rdidx_addr,
1821 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
1822 uc_fw_stat->rx_refill_idx,
1823 uc_fw_stat->rx_num_pkts_indicated,
1824 uc_fw_stat->rx_buf_refilled,
1825 uc_fw_stat->rx_num_ind_drop_no_space,
1826 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08001827 uc_fw_stat->rx_is_suspend,
1828 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001829 /* STATs from IPA */
1830 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301831 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001832 "==== IPA_UC IPA TX ====\n"
1833 "NUM PROCD : %d\n"
1834 "CE DBELL : 0x%x\n"
1835 "NUM DBELL FIRED : %d\n"
1836 "COMP RNG FULL : %d\n"
1837 "COMP RNG EMPT : %d\n"
1838 "COMP RNG USE HGH : %d\n"
1839 "COMP RNG USE LOW : %d\n"
1840 "BAM FIFO FULL : %d\n"
1841 "BAM FIFO EMPT : %d\n"
1842 "BAM FIFO USE HGH : %d\n"
1843 "BAM FIFO USE LOW : %d\n"
1844 "NUM DBELL : %d\n"
1845 "NUM UNEXP DBELL : %d\n"
1846 "NUM BAM INT HDL : 0x%x\n"
1847 "NUM BAM INT NON-RUN : 0x%x\n"
1848 "NUM QMB INT HDL : 0x%x",
1849 ipa_stat.tx_ch_stats.num_pkts_processed,
1850 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
1851 ipa_stat.tx_ch_stats.num_db_fired,
1852 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
1853 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
1854 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
1855 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
1856 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
1857 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
1858 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
1859 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
1860 ipa_stat.tx_ch_stats.num_db,
1861 ipa_stat.tx_ch_stats.num_unexpected_db,
1862 ipa_stat.tx_ch_stats.num_bam_int_handled,
1863 ipa_stat.tx_ch_stats.
1864 num_bam_int_in_non_runnning_state,
1865 ipa_stat.tx_ch_stats.num_qmb_int_handled);
1866
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301867 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001868 "==== IPA_UC IPA RX ====\n"
1869 "MAX OST PKT : %d\n"
1870 "NUM PKT PRCSD : %d\n"
1871 "RNG RP : 0x%x\n"
1872 "COMP RNG FULL : %d\n"
1873 "COMP RNG EMPT : %d\n"
1874 "COMP RNG USE HGH : %d\n"
1875 "COMP RNG USE LOW : %d\n"
1876 "BAM FIFO FULL : %d\n"
1877 "BAM FIFO EMPT : %d\n"
1878 "BAM FIFO USE HGH : %d\n"
1879 "BAM FIFO USE LOW : %d\n"
1880 "NUM DB : %d\n"
1881 "NUM UNEXP DB : %d\n"
1882 "NUM BAM INT HNDL : 0x%x\n",
1883 ipa_stat.rx_ch_stats.max_outstanding_pkts,
1884 ipa_stat.rx_ch_stats.num_pkts_processed,
1885 ipa_stat.rx_ch_stats.rx_ring_rp_value,
1886 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
1887 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
1888 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
1889 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
1890 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
1891 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
1892 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
1893 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
1894 ipa_stat.rx_ch_stats.num_db,
1895 ipa_stat.rx_ch_stats.num_unexpected_db,
1896 ipa_stat.rx_ch_stats.num_bam_int_handled);
1897 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
1898 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
1899 /* STATs from FW */
1900 uc_fw_stat = (struct ipa_uc_fw_stats *)
1901 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301902 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
1904 uc_fw_stat->tx_pkts_completed,
1905 hdd_ipa->ipa_p_tx_packets);
1906 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
1907 (uc_fw_stat->rx_num_ind_drop_no_space +
1908 uc_fw_stat->rx_num_ind_drop_no_buf +
1909 uc_fw_stat->rx_num_pkts_indicated),
1910 hdd_ipa->ipa_p_rx_packets);
1911
1912 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
1913 hdd_ipa->ipa_p_rx_packets =
1914 (uc_fw_stat->rx_num_ind_drop_no_space +
1915 uc_fw_stat->rx_num_ind_drop_no_buf +
1916 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301917 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918 } else {
Yun Park8292dcb2016-10-07 16:46:06 -07001919 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
1920 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001921 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301922 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001923}
1924
1925
1926/**
1927 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
1928 * @adapter: device adapter instance
1929 * @offload_type: MCC or SCC
1930 * @enable: TX offload enable or disable
1931 *
1932 * Return: none
1933 */
1934static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001935 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001937 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001938 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07001939 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001940 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001942 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001943 return;
1944
Yun Park8292dcb2016-10-07 16:46:06 -07001945 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001946 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07001947
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001948 if (!iface_context) {
1949 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1950 "Interface context is NULL");
1951 return;
1952 }
1953
1954 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07001955 /* IPA offload status is already set as desired */
1956 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001957 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
1958 "IPA offload status is already set",
1959 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07001960 return;
1961 }
1962
Yun Park4540e862016-11-10 16:30:06 -08001963 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1964 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1965 "invalid session id: %d, offload_type=%d, enable=%d",
1966 adapter->sessionId, offload_type, enable);
1967 return;
1968 }
1969
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301970 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001971 sizeof(ipa_offload_enable_disable));
1972 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001973 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 ipa_offload_enable_disable.enable = enable;
1975
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301976 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07001977 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001978 ipa_offload_enable_disable.offload_type,
1979 ipa_offload_enable_disable.vdev_id,
1980 ipa_offload_enable_disable.enable);
1981
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301982 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
1984 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301985 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08001986 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
1987 __func__,
1988 ipa_offload_enable_disable.offload_type,
1989 ipa_offload_enable_disable.vdev_id,
1990 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07001991 } else {
1992 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001993 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07001994 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001995 }
1996}
1997
1998/**
1999 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2000 * @work: uC OP work
2001 *
2002 * Return: None
2003 */
2004static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2005{
2006 struct op_msg_type *msg;
2007 struct uc_op_work_struct *uc_op_work = container_of(work,
2008 struct uc_op_work_struct, work);
2009 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2010
2011 cds_ssr_protect(__func__);
2012
2013 msg = uc_op_work->msg;
2014 uc_op_work->msg = NULL;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302015 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002016 "%s, posted msg %d", __func__, msg->op_code);
2017
2018 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2019
2020 cds_ssr_unprotect(__func__);
2021
2022 return;
2023}
2024
2025/**
2026 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2027 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2028 * @op_msg: operation message received from firmware
2029 * @hdd_ctx: Global HDD context
2030 *
2031 * Return: None
2032 */
2033static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2034{
2035 struct hdd_ipa_priv *hdd_ipa;
2036 struct op_msg_type *msg;
2037 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302038 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002039
2040 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302041 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043
2044 msg = (struct op_msg_type *)op_msg;
2045 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2046
2047 if (unlikely(!hdd_ipa))
2048 goto end;
2049
2050 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302051 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052 __func__, msg->op_code);
2053 goto end;
2054 }
2055
2056 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2057 if (uc_op_work->msg)
2058 /* When the same uC OPCODE is already pended, just return */
2059 goto end;
2060
2061 uc_op_work->msg = msg;
2062 schedule_work(&uc_op_work->work);
2063 return;
2064
2065end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302066 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002067}
2068
2069/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002070 * hdd_ipa_init_uc_op_work - init ipa uc op work
2071 * @work: struct work_struct
2072 * @work_handler: work_handler
2073 *
2074 * Return: none
2075 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002076static void hdd_ipa_init_uc_op_work(struct work_struct *work,
2077 work_func_t work_handler)
2078{
2079 INIT_WORK(work, work_handler);
2080}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002081
2082
2083/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2085 * @hdd_ctx: Global HDD context
2086 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302087 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002088 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302089static QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002090{
2091 struct ipa_wdi_in_params pipe_in;
2092 struct ipa_wdi_out_params pipe_out;
2093 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2094 p_cds_contextType cds_ctx = hdd_ctx->pcds_context;
2095 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07002096 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002097
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302098 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2099 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100
Anurag Chouhanffb21542016-02-17 14:33:03 +05302101 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302102 qdf_mutex_create(&ipa_ctxt->event_lock);
2103 qdf_mutex_create(&ipa_ctxt->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002104
2105 /* TX PIPE */
2106 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2107 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2108 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2109 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2110 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2111 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2112 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2113 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2114 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2115 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2116 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2117 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2118 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302119 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002120 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
2121 pipe_in.sys.keep_ipa_awake = true;
2122 }
2123
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002124 pipe_in.u.dl.comp_ring_base_pa =
2125 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002126 pipe_in.u.dl.comp_ring_size =
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002127 ipa_ctxt->ipa_resource.tx_comp_ring_size *
2128 sizeof(qdf_dma_addr_t);
2129 pipe_in.u.dl.ce_ring_base_pa =
2130 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
2131 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
2132 pipe_in.u.dl.ce_ring_size =
2133 ipa_ctxt->ipa_resource.ce_sr_ring_size;
2134 pipe_in.u.dl.num_tx_buffers =
2135 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002136
2137 /* Connect WDI IPA PIPE */
2138 ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
2139 /* Micro Controller Doorbell register */
Govind Singh0487bf22016-08-24 23:08:57 +05302140 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2141 "%s CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
2142 __func__, (unsigned int)pipe_out.uc_door_bell_pa,
2143 ipa_ctxt->tx_pipe_handle);
Leo Chang3bc8fed2015-11-13 10:59:47 -08002144 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145 /* WLAN TX PIPE Handle */
2146 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302147 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002148 "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x,"
2149 " CERZ %d, NB %d, CDBPAD 0x%x",
2150 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
2151 pipe_in.u.dl.comp_ring_size,
2152 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
2153 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
2154 pipe_in.u.dl.ce_ring_size,
2155 pipe_in.u.dl.num_tx_buffers,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002156 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002157
2158 /* RX PIPE */
2159 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2160 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
2161 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
2162 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
2163 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2164 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
2165 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
2166 sizeof(struct sps_iovec);
2167 pipe_in.sys.notify = hdd_ipa_w2i_cb;
2168 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302169 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002170 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
2171 pipe_in.sys.keep_ipa_awake = true;
2172 }
2173
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002174 pipe_in.u.ul.rdy_ring_base_pa =
2175 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
2176 pipe_in.u.ul.rdy_ring_size =
2177 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
2178 pipe_in.u.ul.rdy_ring_rp_pa =
2179 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002180 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002181 ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
Leo Chang3bc8fed2015-11-13 10:59:47 -08002182 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002183 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302184 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002185 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
2186 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
2187 pipe_in.u.ul.rdy_ring_size,
2188 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002189 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002190
Leo Changfdb45c32016-10-28 11:09:23 -07002191 cdp_ipa_set_doorbell_paddr(soc, cds_ctx->pdev_txrx_ctx,
2192 ipa_ctxt->tx_comp_doorbell_paddr,
2193 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194
Leo Changfdb45c32016-10-28 11:09:23 -07002195 cdp_ipa_register_op_cb(soc, cds_ctx->pdev_txrx_ctx,
2196 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002197
2198 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08002199 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002200 hdd_ipa_uc_fw_op_event_handler);
2201 ipa_ctxt->uc_op_work[i].msg = NULL;
2202 }
2203
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302204 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002205}
2206
Leo Change3e49442015-10-26 20:07:13 -07002207/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002208 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002209 * @hdd_ctx: hdd main context
2210 *
2211 * Force shutdown IPA pipe
2212 * Independent of FW pipe status, IPA pipe shutdonw progress
2213 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2214 * independent from FW pipe status
2215 *
2216 * Return: NONE
2217 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002218static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002219{
2220 struct hdd_ipa_priv *hdd_ipa;
2221
2222 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2223 return;
2224
2225 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2226 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302227 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07002228 "IPA pipes are not down yet, force shutdown");
2229 hdd_ipa_uc_disable_pipes(hdd_ipa);
2230 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302231 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Leo Change3e49442015-10-26 20:07:13 -07002232 "IPA pipes are down, do nothing");
2233 }
2234
2235 return;
2236}
2237
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002238/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002239 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2240 * __hdd_ipa_uc_force_pipe_shutdown
2241 * @hdd_ctx: hdd main context
2242 *
2243 * Force shutdown IPA pipe
2244 * Independent of FW pipe status, IPA pipe shutdonw progress
2245 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2246 * independent from FW pipe status
2247 *
2248 * Return: NONE
2249 */
2250void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2251{
2252 cds_ssr_protect(__func__);
2253 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2254 cds_ssr_unprotect(__func__);
2255}
2256
2257/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302258 * hdd_ipa_msg_free_fn() - Free an IPA message
2259 * @buff: pointer to the IPA message
2260 * @len: length of the IPA message
2261 * @type: type of IPA message
2262 *
2263 * Return: None
2264 */
2265static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2266{
2267 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "msg type:%d, len:%d", type, len);
2268 ghdd_ipa->stats.num_free_msg++;
2269 qdf_mem_free(buff);
2270}
2271
Govind Singh9c58eba2016-09-02 16:23:06 +05302272/**
jge62037862016-12-09 10:44:33 +08002273 * hdd_ipa_uc_send_evt() - send event to ipa
2274 * @hdd_ctx: pointer to hdd context
2275 * @type: event type
2276 * @mac_addr: pointer to mac address
2277 *
2278 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05302279 *
2280 * Return: 0 - Success
2281 */
jge62037862016-12-09 10:44:33 +08002282static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
2283 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05302284{
jge62037862016-12-09 10:44:33 +08002285 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05302286 struct ipa_msg_meta meta;
2287 struct ipa_wlan_msg *msg;
2288 int ret = 0;
jge62037862016-12-09 10:44:33 +08002289
2290 meta.msg_len = sizeof(struct ipa_wlan_msg);
2291 msg = qdf_mem_malloc(meta.msg_len);
2292 if (msg == NULL) {
2293 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2294 "msg allocation failed");
2295 return -ENOMEM;
2296 }
2297
2298 meta.msg_type = type;
2299 strlcpy(msg->name, adapter->dev->name,
2300 IPA_RESOURCE_NAME_MAX);
2301 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
2302 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
2303 msg->name, meta.msg_type);
2304 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2305 if (ret) {
2306 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2307 "%s: Evt: %d fail:%d",
2308 msg->name, meta.msg_type, ret);
2309 qdf_mem_free(msg);
2310 return ret;
2311 }
2312
2313 hdd_ipa->stats.num_send_msg++;
2314
2315 return ret;
2316}
2317
2318/**
2319 * hdd_ipa_uc_disconnect_client() - send client disconnect event
2320 * @hdd_ctx: pointer to hdd adapter
2321 *
2322 * Send disconnect client event to IPA driver during SSR
2323 *
2324 * Return: 0 - Success
2325 */
2326static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
2327{
2328 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2329 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05302330 int i;
2331
2332 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2333 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2334 continue;
2335 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08002336 (!adapter->aStaInfo[i].isDeauthInProgress) &&
2337 hdd_ipa->sap_num_connected_sta) {
2338 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
2339 adapter->aStaInfo[i].macAddrSTA.bytes);
2340 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05302341 }
2342 }
2343
2344 return ret;
2345}
2346
2347/**
jge62037862016-12-09 10:44:33 +08002348 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
2349 * @hdd_ctx: pointer to hdd adapter
2350 *
2351 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05302352 *
2353 * Return: 0 - Success
2354 */
jge62037862016-12-09 10:44:33 +08002355
2356static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
2357{
2358 int ret = 0;
2359
2360 if (adapter->ipa_context)
2361 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
2362 adapter->dev->dev_addr);
2363
2364 return ret;
2365}
2366
2367#ifdef IPA_UC_STA_OFFLOAD
2368/**
2369 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
2370 * @hdd_ctx: pointer to hdd adapter
2371 *
2372 * Send disconnect sta event to IPA driver during SSR
2373 *
2374 * Return: 0 - Success
2375 */
2376static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2377{
2378 hdd_station_ctx_t *pHddStaCtx;
2379 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2380 int ret = 0;
2381
2382 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa) &&
2383 hdd_ipa->sta_connected) {
2384 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2385 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
2386 pHddStaCtx->conn_info.bssId);
2387 }
2388
2389 return ret;
2390}
2391#else
2392static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2393{
2394 return 0;
2395}
2396
2397#endif
2398
2399/**
2400 * hdd_ipa_uc_disconnect() - send disconnect ipa event
2401 * @hdd_ctx: pointer to hdd context
2402 *
2403 * Send disconnect event to IPA driver during SSR
2404 *
2405 * Return: 0 - Success
2406 */
2407static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05302408{
2409 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2410 QDF_STATUS status;
2411 hdd_adapter_t *adapter;
2412 int ret = 0;
2413
Govind Singh9c58eba2016-09-02 16:23:06 +05302414 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2415 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2416 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08002417 if (adapter->device_mode == QDF_SAP_MODE) {
2418 hdd_ipa_uc_disconnect_client(adapter);
2419 hdd_ipa_uc_disconnect_ap(adapter);
2420 } else if (adapter->device_mode == QDF_STA_MODE) {
2421 hdd_ipa_uc_disconnect_sta(adapter);
2422 }
2423
Govind Singh9c58eba2016-09-02 16:23:06 +05302424 status = hdd_get_next_adapter(
2425 hdd_ctx, adapter_node, &next);
2426 adapter_node = next;
2427 }
2428
2429 return ret;
2430}
2431
2432/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002433 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002434 *
2435 * Deinit basic IPA UC host side to be in sync reloaded FW during
2436 * SSR
2437 *
2438 * Return: 0 - Success
2439 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002440static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002441{
2442 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2443 int idx;
2444 struct hdd_ipa_iface_context *iface_context;
2445
Leo Chang3bc8fed2015-11-13 10:59:47 -08002446 if ((!hdd_ipa) || (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002447 return 0;
2448
jge62037862016-12-09 10:44:33 +08002449 /* send disconnect to ipa driver */
2450 hdd_ipa_uc_disconnect(hdd_ipa->hdd_ctx);
2451
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002452 /* Clean up HDD IPA interfaces */
2453 for (idx = 0; (hdd_ipa->num_iface > 0) &&
2454 (idx < HDD_IPA_MAX_IFACE); idx++) {
2455 iface_context = &hdd_ipa->iface_context[idx];
2456 if (iface_context && iface_context->adapter)
2457 hdd_ipa_cleanup_iface(iface_context);
2458 }
2459
2460 /* After SSR, wlan driver reloads FW again. But we need to protect
2461 * IPA submodule during SSR transient state. So deinit basic IPA
2462 * UC host side to be in sync with reloaded FW during SSR
2463 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08002464 if (!hdd_ipa->ipa_pipes_down)
2465 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002466
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302467 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002468 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2469 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
2470 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
2471 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302472 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002473
Guolei Bianca144d82016-11-10 11:07:42 +08002474 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
2475 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
2476
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002477 /* Full IPA driver cleanup not required since wlan driver is now
2478 * unloaded and reloaded after SSR.
2479 */
2480 return 0;
2481}
2482
2483/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002484 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
2485 *
2486 * Deinit basic IPA UC host side to be in sync reloaded FW during
2487 * SSR
2488 *
2489 * Return: 0 - Success
2490 */
2491int hdd_ipa_uc_ssr_deinit(void)
2492{
2493 int ret;
2494
2495 cds_ssr_protect(__func__);
2496 ret = __hdd_ipa_uc_ssr_deinit();
2497 cds_ssr_unprotect(__func__);
2498
2499 return ret;
2500}
2501
2502/**
2503 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002504 *
2505 * Init basic IPA UC host side to be in sync with reloaded FW after
2506 * SSR to resume IPA UC operations
2507 *
2508 * Return: 0 - Success
2509 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002510static int __hdd_ipa_uc_ssr_reinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002511{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002512
2513 /* After SSR is complete, IPA UC can resume operation. But now wlan
2514 * driver will be unloaded and reloaded, which takes care of IPA cleanup
2515 * and initialization. This is a placeholder func if IPA has to resume
2516 * operations without driver reload.
2517 */
2518 return 0;
2519}
Leo Chang3bc8fed2015-11-13 10:59:47 -08002520
2521/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002522 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
2523 *
2524 * Init basic IPA UC host side to be in sync with reloaded FW after
2525 * SSR to resume IPA UC operations
2526 *
2527 * Return: 0 - Success
2528 */
2529int hdd_ipa_uc_ssr_reinit(void)
2530{
2531 int ret;
2532
2533 cds_ssr_protect(__func__);
2534 ret = __hdd_ipa_uc_ssr_reinit();
2535 cds_ssr_unprotect(__func__);
2536
2537 return ret;
2538}
2539
2540/**
2541 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08002542 * @hdd_ctx: Global HDD context
2543 * @skb: skb sent to IPA
2544 * @session_id: send packet instance session id
2545 *
2546 * Send TX packet which generated by system to IPA.
2547 * This routine only will be used for function verification
2548 *
2549 * Return: NULL packet sent to IPA properly
2550 * NULL invalid packet drop
2551 * skb packet not sent to IPA. legacy data path should handle
2552 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002553static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002554 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07002555{
Leo Chang3bc8fed2015-11-13 10:59:47 -08002556 struct ipa_header *ipa_header;
2557 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002558 struct hdd_ipa_priv *hdd_ipa;
2559
2560 if (wlan_hdd_validate_context(hdd_ctx))
2561 return skb;
2562
2563 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002564
2565 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2566 return skb;
2567
Leo Chang07b28f62016-05-11 12:29:22 -07002568 if (!hdd_ipa)
2569 return skb;
2570
2571 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
2572 return skb;
2573
Leo Changcc923e22016-06-16 15:29:03 -07002574 if (skb_headroom(skb) <
2575 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07002576 return skb;
2577
Leo Chang3bc8fed2015-11-13 10:59:47 -08002578 ipa_header = (struct ipa_header *) skb_push(skb,
2579 sizeof(struct ipa_header));
2580 if (!ipa_header) {
2581 /* No headroom, legacy */
2582 return skb;
2583 }
2584 memset(ipa_header, 0, sizeof(*ipa_header));
2585 ipa_header->vdev_id = 0;
2586
2587 frag_header = (struct frag_header *) skb_push(skb,
2588 sizeof(struct frag_header));
2589 if (!frag_header) {
2590 /* No headroom, drop */
2591 kfree_skb(skb);
2592 return NULL;
2593 }
2594 memset(frag_header, 0, sizeof(*frag_header));
2595 frag_header->length = skb->len - sizeof(struct frag_header)
2596 - sizeof(struct ipa_header);
2597
2598 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
2599 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07002600}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002601
2602/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002603 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
2604 * @hdd_ctx: Global HDD context
2605 * @skb: skb sent to IPA
2606 * @session_id: send packet instance session id
2607 *
2608 * Send TX packet which generated by system to IPA.
2609 * This routine only will be used for function verification
2610 *
2611 * Return: NULL packet sent to IPA properly
2612 * NULL invalid packet drop
2613 * skb packet not sent to IPA. legacy data path should handle
2614 */
2615struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
2616 struct sk_buff *skb, uint8_t session_id)
2617{
2618 struct sk_buff *ret;
2619
2620 cds_ssr_protect(__func__);
2621 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
2622 cds_ssr_unprotect(__func__);
2623
2624 return ret;
2625}
2626
2627/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002628 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
2629 * @work: scheduled work
2630 *
2631 * When IPA resources are released in hdd_ipa_rm_try_release() we do
2632 * not want to immediately release the wake lock since the system
2633 * would then potentially try to suspend when there is a healthy data
2634 * rate. Deferred work is scheduled and this function handles the
2635 * work. When this function is called, if the IPA resource is still
2636 * released then we release the wake lock.
2637 *
2638 * Return: None
2639 */
2640static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
2641{
2642 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
2643 struct hdd_ipa_priv,
2644 wake_lock_work);
2645
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302646 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002647
2648 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
2649 goto end;
2650
2651 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302652 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002653 WIFI_POWER_EVENT_WAKELOCK_IPA);
2654
2655end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302656 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002657}
2658
2659/**
2660 * hdd_ipa_rm_request() - Request resource from IPA
2661 * @hdd_ipa: Global HDD IPA context
2662 *
2663 * Return: 0 on success, negative errno on error
2664 */
2665static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
2666{
2667 int ret = 0;
2668
2669 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2670 return 0;
2671
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302672 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002673
2674 switch (hdd_ipa->rm_state) {
2675 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302676 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002677 return 0;
2678 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302679 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002680 return -EINPROGRESS;
2681 case HDD_IPA_RM_RELEASED:
2682 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
2683 break;
2684 }
2685
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302686 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002687
2688 ret = ipa_rm_inactivity_timer_request_resource(
2689 IPA_RM_RESOURCE_WLAN_PROD);
2690
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302691 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002692 if (ret == 0) {
2693 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
2694 hdd_ipa->stats.num_rm_grant_imm++;
2695 }
2696
2697 cancel_delayed_work(&hdd_ipa->wake_lock_work);
2698 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302699 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002700 WIFI_POWER_EVENT_WAKELOCK_IPA);
2701 hdd_ipa->wake_lock_released = false;
2702 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302703 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002704
2705 return ret;
2706}
2707
2708/**
2709 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
2710 * @hdd_ipa: Global HDD IPA context
2711 *
2712 * Return: 0 if resources released, negative errno otherwise
2713 */
2714static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
2715{
2716 int ret = 0;
2717
2718 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2719 return 0;
2720
2721 if (atomic_read(&hdd_ipa->tx_ref_cnt))
2722 return -EAGAIN;
2723
2724 spin_lock_bh(&hdd_ipa->q_lock);
2725 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
2726 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
2727 spin_unlock_bh(&hdd_ipa->q_lock);
2728 return -EAGAIN;
2729 }
2730 spin_unlock_bh(&hdd_ipa->q_lock);
2731
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302732 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002733
Nirav Shahcbc6d722016-03-01 16:24:53 +05302734 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302735 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002736 return -EAGAIN;
2737 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302738 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002739
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302740 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002741 switch (hdd_ipa->rm_state) {
2742 case HDD_IPA_RM_GRANTED:
2743 break;
2744 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302745 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002746 return -EINPROGRESS;
2747 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302748 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002749 return 0;
2750 }
2751
2752 /* IPA driver returns immediately so set the state here to avoid any
2753 * race condition.
2754 */
2755 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
2756 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302757 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002758
2759 ret =
2760 ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
2761
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302762 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002763 if (unlikely(ret != 0)) {
2764 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
2765 WARN_ON(1);
2766 }
2767
2768 /*
2769 * If wake_lock is released immediately, kernel would try to suspend
2770 * immediately as well, Just avoid ping-pong between suspend-resume
2771 * while there is healthy amount of data transfer going on by
2772 * releasing the wake_lock after some delay.
2773 */
2774 schedule_delayed_work(&hdd_ipa->wake_lock_work,
2775 msecs_to_jiffies
2776 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
2777
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302778 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002779
2780 return ret;
2781}
2782
2783/**
2784 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
2785 * @user_data: user data registered with IPA
2786 * @event: the IPA resource manager event that occurred
2787 * @data: the data associated with the event
2788 *
2789 * Return: None
2790 */
2791static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
2792 unsigned long data)
2793{
2794 struct hdd_ipa_priv *hdd_ipa = user_data;
2795
2796 if (unlikely(!hdd_ipa))
2797 return;
2798
2799 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2800 return;
2801
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302802 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002803
2804 switch (event) {
2805 case IPA_RM_RESOURCE_GRANTED:
2806 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2807 /* RM Notification comes with ISR context
2808 * it should be serialized into work queue to avoid
2809 * ISR sleep problem
2810 */
2811 hdd_ipa->uc_rm_work.event = event;
2812 schedule_work(&hdd_ipa->uc_rm_work.work);
2813 break;
2814 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302815 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002816 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302817 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002818 hdd_ipa->stats.num_rm_grant++;
2819 break;
2820
2821 case IPA_RM_RESOURCE_RELEASED:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302822 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002823 hdd_ipa->resource_unloading = false;
2824 break;
2825
2826 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302827 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002828 break;
2829 }
2830}
2831
2832/**
2833 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
2834 *
2835 * Callback function registered with IPA that is called when IPA wants
2836 * to release the WLAN consumer resource
2837 *
2838 * Return: 0 if the request is granted, negative errno otherwise
2839 */
2840static int hdd_ipa_rm_cons_release(void)
2841{
2842 return 0;
2843}
2844
2845/**
2846 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
2847 *
2848 * Callback function registered with IPA that is called when IPA wants
2849 * to access the WLAN consumer resource
2850 *
2851 * Return: 0 if the request is granted, negative errno otherwise
2852 */
2853static int hdd_ipa_rm_cons_request(void)
2854{
Yun Park4d8b60a2015-10-22 13:59:32 -07002855 int ret = 0;
2856
2857 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302858 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07002859 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002860 __func__);
2861 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07002862 ret = -EINPROGRESS;
2863 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302864 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07002865 "%s: IPA resource unloading in progress",
2866 __func__);
2867 ghdd_ipa->pending_cons_req = true;
2868 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002869 }
Yun Park4d8b60a2015-10-22 13:59:32 -07002870
2871 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002872}
2873
2874/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002875 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002876 * @hdd_ctx: Global HDD context
2877 * @tx_packets: Number of packets transmitted in the last sample period
2878 * @rx_packets: Number of packets received in the last sample period
2879 *
2880 * Return: 0 on success, negative errno on error
2881 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002882static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002883 uint64_t rx_packets)
2884{
2885 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002886 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002887 struct ipa_rm_perf_profile profile;
2888 int ret;
2889
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002890 if (wlan_hdd_validate_context(hdd_ctx))
2891 return 0;
2892
2893 hdd_ipa = hdd_ctx->hdd_ipa;
2894
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002895 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
2896 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
2897 return 0;
2898
2899 memset(&profile, 0, sizeof(profile));
2900
2901 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
2902 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
2903 else if (tx_packets >
2904 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
2905 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
2906 else
2907 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
2908
2909 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
2910 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
2911 else if (rx_packets >
2912 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
2913 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
2914 else
2915 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
2916
Yun Park8f289c82016-10-18 16:38:21 -07002917 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002918 "CONS perf curr: %d, next: %d",
2919 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Park8f289c82016-10-18 16:38:21 -07002920 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002921 "PROD perf curr: %d, next: %d",
2922 hdd_ipa->curr_prod_bw, next_prod_bw);
2923
2924 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08002925 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002926 hdd_ipa->curr_cons_bw, next_cons_bw);
2927 profile.max_supported_bandwidth_mbps = next_cons_bw;
2928 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
2929 &profile);
2930 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08002931 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002932
2933 return ret;
2934 }
2935 hdd_ipa->curr_cons_bw = next_cons_bw;
2936 hdd_ipa->stats.num_cons_perf_req++;
2937 }
2938
2939 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08002940 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002941 hdd_ipa->curr_prod_bw, next_prod_bw);
2942 profile.max_supported_bandwidth_mbps = next_prod_bw;
2943 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
2944 &profile);
2945 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08002946 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002947 return ret;
2948 }
2949 hdd_ipa->curr_prod_bw = next_prod_bw;
2950 hdd_ipa->stats.num_prod_perf_req++;
2951 }
2952
2953 return 0;
2954}
2955
2956/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002957 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
2958 * @hdd_ctx: Global HDD context
2959 * @tx_packets: Number of packets transmitted in the last sample period
2960 * @rx_packets: Number of packets received in the last sample period
2961 *
2962 * Return: 0 on success, negative errno on error
2963 */
2964int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
2965 uint64_t rx_packets)
2966{
2967 int ret;
2968
2969 cds_ssr_protect(__func__);
2970 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
2971 cds_ssr_unprotect(__func__);
2972
2973 return ret;
2974}
2975
2976/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002977 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
2978 * @work: struct work_struct
2979 * @work_handler: work_handler
2980 *
2981 * Return: none
2982 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002983static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
2984 work_func_t work_handler)
2985{
2986 INIT_WORK(work, work_handler);
2987}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002988
2989/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002990 * hdd_ipa_setup_rm() - Setup IPA resource management
2991 * @hdd_ipa: Global HDD IPA context
2992 *
2993 * Return: 0 on success, negative errno on error
2994 */
2995static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
2996{
2997 struct ipa_rm_create_params create_params = { 0 };
2998 int ret;
2999
3000 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3001 return 0;
3002
Rajeev Kumar217f2172016-01-06 18:11:55 -08003003 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3004 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003005 memset(&create_params, 0, sizeof(create_params));
3006 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3007 create_params.reg_params.user_data = hdd_ipa;
3008 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3009 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3010
3011 ret = ipa_rm_create_resource(&create_params);
3012 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303013 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014 "Create RM resource failed: %d", ret);
3015 goto setup_rm_fail;
3016 }
3017
3018 memset(&create_params, 0, sizeof(create_params));
3019 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3020 create_params.request_resource = hdd_ipa_rm_cons_request;
3021 create_params.release_resource = hdd_ipa_rm_cons_release;
3022 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3023
3024 ret = ipa_rm_create_resource(&create_params);
3025 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303026 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003027 "Create RM CONS resource failed: %d", ret);
3028 goto delete_prod;
3029 }
3030
3031 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3032 IPA_RM_RESOURCE_APPS_CONS);
3033
3034 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3035 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3036 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303037 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003038 ret);
3039 goto timer_init_failed;
3040 }
3041
3042 /* Set the lowest bandwidth to start with */
3043 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3044
3045 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303046 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003047 "Set perf level failed: %d", ret);
3048 goto set_perf_failed;
3049 }
3050
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303051 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003052 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3053 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303054 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3056 hdd_ipa->wake_lock_released = true;
3057 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3058
3059 return ret;
3060
3061set_perf_failed:
3062 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3063
3064timer_init_failed:
3065 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3066
3067delete_prod:
3068 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3069
3070setup_rm_fail:
3071 return ret;
3072}
3073
3074/**
3075 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3076 * @hdd_ipa: Global HDD IPA context
3077 *
3078 * Destroys all resources associated with the IPA resource manager
3079 *
3080 * Return: None
3081 */
3082static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3083{
3084 int ret;
3085
3086 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3087 return;
3088
3089 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303090 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003091
3092#ifdef WLAN_OPEN_SOURCE
3093 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
3094#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303095 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003096
3097 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3098
3099 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3100 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303101 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003102 "RM PROD resource delete failed %d", ret);
3103
3104 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3105 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303106 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003107 "RM CONS resource delete failed %d", ret);
3108}
3109
3110/**
3111 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3112 * @skb: network buffer
3113 * @adapter: network adapter
3114 *
3115 * Called when a network buffer is received which should not be routed
3116 * to the IPA module.
3117 *
3118 * Return: None
3119 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303120static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003121 hdd_adapter_t *adapter)
3122{
3123 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3124 unsigned int cpu_index;
3125
3126 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303127 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003128 adapter);
3129 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003130 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003131 return;
3132 }
3133
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003134 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003136 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003137 return;
3138 }
3139
3140 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3141 skb->dev = adapter->dev;
3142 skb->protocol = eth_type_trans(skb, skb->dev);
3143 skb->ip_summed = CHECKSUM_NONE;
3144
3145 cpu_index = wlan_hdd_get_cpu();
3146
3147 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
3148 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
3149 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3150 else
3151 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3152
3153 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
3154 adapter->dev->last_rx = jiffies;
3155}
3156
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003157/**
Leo Chang69c39692016-10-12 20:11:12 -07003158 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3159 * @hdd_ipa: pointer to hdd ipa context
3160 * @adapter: network adapter
3161 * @skb: data pointer
3162 *
3163 * if exception packet has set forward bit, copied new packet should be
3164 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3165 * put into pm queue and tx procedure will be differed
3166 *
3167 * Return: None
3168 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003169static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
3170 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003171{
Leo Chang69c39692016-10-12 20:11:12 -07003172 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3173
Leo Chang69c39692016-10-12 20:11:12 -07003174 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
3175 /* WLAN subsystem is in suspend, put int queue */
3176 if (hdd_ipa->suspended) {
3177 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3178 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3179 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003180 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3181 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003182 pm_tx_cb->exception = true;
3183 pm_tx_cb->adapter = adapter;
3184 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003185 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003186 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3187 hdd_ipa->stats.num_tx_queued++;
3188 } else {
3189 /* Resume, put packet into WLAN TX */
3190 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003191 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003192 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3193 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003194 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003195 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003196 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003197 hdd_ipa->ipa_tx_forward++;
3198 }
3199 }
3200}
3201
3202/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003203 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3204 * @hdd_ipa: pointer to HDD IPA struct
3205 * @adapter: hdd adapter pointer
3206 * @desc: Firmware descriptor
3207 * @skb: Data buffer
3208 *
3209 * Return:
3210 * HDD_IPA_FORWARD_PKT_NONE
3211 * HDD_IPA_FORWARD_PKT_DISCARD
3212 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3213 *
3214 */
3215
3216static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3217 struct hdd_ipa_priv *hdd_ipa,
3218 hdd_adapter_t *adapter,
3219 uint8_t desc,
3220 qdf_nbuf_t skb)
3221{
3222 int ret = HDD_IPA_FORWARD_PKT_NONE;
3223
3224 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303225 if (!ol_txrx_fwd_desc_thresh_check(
3226 ol_txrx_get_vdev_from_vdev_id(adapter->sessionId))) {
3227 /* Drop the packet*/
3228 hdd_ipa->stats.num_tx_fwd_err++;
3229 kfree_skb(skb);
3230 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3231 return ret;
3232 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003233 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3234 "Forward packet to Tx (fw_desc=%d)", desc);
3235 hdd_ipa->ipa_tx_forward++;
3236
3237 if ((desc & FW_RX_DESC_DISCARD_M)) {
3238 hdd_ipa_forward(hdd_ipa, adapter, skb);
3239 hdd_ipa->ipa_rx_internel_drop_count++;
3240 hdd_ipa->ipa_rx_discard++;
3241 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3242 } else {
3243 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
3244 if (cloned_skb)
3245 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3246 else
3247 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3248 "%s: tx skb alloc failed",
3249 __func__);
3250 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3251 }
3252 }
3253
3254 return ret;
3255}
3256
3257/**
Leo Chang69c39692016-10-12 20:11:12 -07003258 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003259 * @priv: pointer to private data registered with IPA (we register a
3260 * pointer to the global IPA context)
3261 * @evt: the IPA event which triggered the callback
3262 * @data: data associated with the event
3263 *
3264 * Return: None
3265 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003266static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003267 unsigned long data)
3268{
3269 struct hdd_ipa_priv *hdd_ipa = NULL;
3270 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303271 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272 uint8_t iface_id;
3273 uint8_t session_id;
3274 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003275 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003276 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003277
3278 hdd_ipa = (struct hdd_ipa_priv *)priv;
3279
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003280 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3281 return;
3282
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003283 switch (evt) {
3284 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303285 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003286
3287 /*
3288 * When SSR is going on or driver is unloading,
3289 * just drop the packets.
3290 */
3291 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
3292 if (0 != status) {
3293 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3294 "Invalid context: drop packet");
3295 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3296 kfree_skb(skb);
3297 return;
3298 }
3299
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003300 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3301 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003302 iface_id = hdd_ipa->vdev_to_iface[session_id];
Govind Singhb6a89772016-08-12 11:23:35 +05303303 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003304 "IPA_RECEIVE: session_id=%u, iface_id=%u",
3305 session_id, iface_id);
3306 } else {
3307 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
3308 }
3309
3310 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303311 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003312 "IPA_RECEIVE: Invalid iface_id: %u",
3313 iface_id);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303314 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_INFO_HIGH,
Yun Parkb187d542016-11-14 18:10:04 -08003315 "w2i -- skb",
3316 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003317 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003318 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003319 return;
3320 }
3321
3322 iface_context = &hdd_ipa->iface_context[iface_id];
3323 adapter = iface_context->adapter;
3324
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303325 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003326 "w2i -- skb",
3327 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003328 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3329 hdd_ipa->stats.num_rx_excep++;
3330 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
3331 } else {
3332 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
3333 }
3334
3335 iface_context->stats.num_rx_ipa_excep++;
3336
3337 /* Disable to forward Intra-BSS Rx packets when
3338 * ap_isolate=1 in hostapd.conf
3339 */
Yun Park046101c2016-09-02 15:32:14 -07003340 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003341 /*
3342 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3343 * all Rx packets to IPA uC, which need to be forwarded
3344 * to other interface.
3345 * And, IPA driver will send back to WLAN host driver
3346 * through exception pipe with fw_desc field set by FW.
3347 * Here we are checking fw_desc field for FORWARD bit
3348 * set, and forward to Tx. Then copy to kernel stack
3349 * only when DISCARD bit is not set.
3350 */
3351 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003352 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3353 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3354 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003355 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003356 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303357 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003358 "Intra-BSS FWD is disabled-skip forward to Tx");
3359 }
3360
3361 hdd_ipa_send_skb_to_network(skb, adapter);
3362 break;
3363
3364 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303365 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003366 "w2i cb wrong event: 0x%x", evt);
3367 return;
3368 }
3369}
3370
3371/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003372 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3373 * @priv: pointer to private data registered with IPA (we register a
3374 * pointer to the global IPA context)
3375 * @evt: the IPA event which triggered the callback
3376 * @data: data associated with the event
3377 *
3378 * Return: None
3379 */
3380static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3381 unsigned long data)
3382{
3383 cds_ssr_protect(__func__);
3384 __hdd_ipa_w2i_cb(priv, evt, data);
3385 cds_ssr_unprotect(__func__);
3386}
3387
3388/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003389 * hdd_ipa_nbuf_cb() - IPA TX complete callback
3390 * @skb: packet buffer which was transmitted
3391 *
3392 * Return: None
3393 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303394void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003395{
3396 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3397
Govind Singhb6a89772016-08-12 11:23:35 +05303398 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05303399 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003400 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303401 ipa_free_skb((struct ipa_rx_data *)
3402 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403
3404 hdd_ipa->stats.num_tx_comp_cnt++;
3405
3406 atomic_dec(&hdd_ipa->tx_ref_cnt);
3407
3408 hdd_ipa_rm_try_release(hdd_ipa);
3409}
3410
3411/**
3412 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
3413 * @iface_context: interface-specific IPA context
3414 * @ipa_tx_desc: packet data descriptor
3415 *
3416 * Return: None
3417 */
3418static void hdd_ipa_send_pkt_to_tl(
3419 struct hdd_ipa_iface_context *iface_context,
3420 struct ipa_rx_data *ipa_tx_desc)
3421{
3422 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303424 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003425
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303426 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003427 adapter = iface_context->adapter;
3428 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303429 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003430 ipa_free_skb(ipa_tx_desc);
3431 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303432 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433 hdd_ipa_rm_try_release(hdd_ipa);
3434 return;
3435 }
3436
3437 /*
3438 * During CAC period, data packets shouldn't be sent over the air so
3439 * drop all the packets here
3440 */
3441 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
3442 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303443 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003444 iface_context->stats.num_tx_cac_drop++;
3445 hdd_ipa_rm_try_release(hdd_ipa);
3446 return;
3447 }
3448
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003449 ++adapter->stats.tx_packets;
3450
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303451 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452
3453 skb = ipa_tx_desc->skb;
3454
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303455 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303456 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003457 /* FIXME: This is broken. No such field in cb any more:
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08003458 * NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb;
3459 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003460 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05303461 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003462 ipa_tx_desc->dma_addr
3463 + HDD_IPA_WLAN_FRAG_HEADER
3464 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003465 ipa_tx_desc->skb->len -=
3466 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
3467 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05303468 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003469
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003470 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303471 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003472
3473 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
3474
Leo Changfdb45c32016-10-28 11:09:23 -07003475 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
3476 iface_context->tl_context, ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003477 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303478 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479 ipa_free_skb(ipa_tx_desc);
3480 iface_context->stats.num_tx_err++;
3481 hdd_ipa_rm_try_release(hdd_ipa);
3482 return;
3483 }
3484
3485 atomic_inc(&hdd_ipa->tx_ref_cnt);
3486
3487 iface_context->stats.num_tx++;
3488
3489}
3490
3491/**
Leo Chang11545d62016-10-17 14:53:50 -07003492 * hdd_ipa_is_present() - get IPA hw status
3493 * @hdd_ctx: pointer to hdd context
3494 *
3495 * ipa_uc_reg_rdyCB is not directly designed to check
3496 * ipa hw status. This is an undocumented function which
3497 * has confirmed with IPA team.
3498 *
3499 * Return: true - ipa hw present
3500 * false - ipa hw not present
3501 */
3502bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
3503{
3504 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07003505 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07003506 return true;
3507 else
3508 return false;
3509}
3510
3511/**
Leo Chang69c39692016-10-12 20:11:12 -07003512 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003513 * @work: pointer to the scheduled work
3514 *
3515 * Called during PM resume to send packets to TL which were queued
3516 * while host was in the process of suspending.
3517 *
3518 * Return: None
3519 */
Leo Chang69c39692016-10-12 20:11:12 -07003520static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003521{
3522 struct hdd_ipa_priv *hdd_ipa = container_of(work,
3523 struct hdd_ipa_priv,
3524 pm_work);
3525 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303526 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003527 uint32_t dequeued = 0;
3528
Leo Chang69c39692016-10-12 20:11:12 -07003529 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
3530 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303531 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303532 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
3533 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303534 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003535
3536 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003537 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07003538 if (pm_tx_cb->exception) {
3539 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3540 "FLUSH EXCEPTION");
3541 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
3542 } else {
3543 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003544 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07003545 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303546 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003547 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303548 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07003549 qdf_wake_lock_release(&hdd_ipa->wake_lock,
3550 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003551
3552 hdd_ipa->stats.num_tx_dequeued += dequeued;
3553 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
3554 hdd_ipa->stats.num_max_pm_queue = dequeued;
3555}
3556
3557/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003558 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003559 * @priv: pointer to private data registered with IPA (we register a
3560 * pointer to the interface-specific IPA context)
3561 * @evt: the IPA event which triggered the callback
3562 * @data: data associated with the event
3563 *
3564 * Return: None
3565 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003566static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003567 unsigned long data)
3568{
3569 struct hdd_ipa_priv *hdd_ipa = NULL;
3570 struct ipa_rx_data *ipa_tx_desc;
3571 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303572 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003573 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303574 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003575
Mukul Sharma81661ae2015-10-30 20:26:02 +05303576 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003577 ipa_tx_desc = (struct ipa_rx_data *)data;
3578 hdd_ipa = iface_context->hdd_ipa;
3579
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003580 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003581 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
3582 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003583 iface_context->stats.num_tx_drop++;
3584 return;
3585 }
3586
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003587 /*
3588 * When SSR is going on or driver is unloading, just drop the packets.
3589 * During SSR, there is no use in queueing the packets as STA has to
3590 * connect back any way
3591 */
3592 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303593 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003594 ipa_free_skb(ipa_tx_desc);
3595 iface_context->stats.num_tx_drop++;
3596 return;
3597 }
3598
3599 skb = ipa_tx_desc->skb;
3600
Yun Parkb187d542016-11-14 18:10:04 -08003601 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
3602 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003603
3604 /*
3605 * If PROD resource is not requested here then there may be cases where
3606 * IPA hardware may be clocked down because of not having proper
3607 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
3608 * workaround to request PROD resource while data is going over CONS
3609 * pipe to prevent the IPA hardware clockdown.
3610 */
3611 hdd_ipa_rm_request(hdd_ipa);
3612
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303613 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003614 /*
3615 * If host is still suspended then queue the packets and these will be
3616 * drained later when resume completes. When packet is arrived here and
3617 * host is suspended, this means that there is already resume is in
3618 * progress.
3619 */
3620 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303621 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003622 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
3623 pm_tx_cb->iface_context = iface_context;
3624 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303625 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003626 hdd_ipa->stats.num_tx_queued++;
3627
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303628 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003629 return;
3630 }
3631
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303632 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003633
3634 /*
3635 * If we are here means, host is not suspended, wait for the work queue
3636 * to finish.
3637 */
3638#ifdef WLAN_OPEN_SOURCE
3639 flush_work(&hdd_ipa->pm_work);
3640#endif
3641
3642 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
3643}
3644
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003645/*
3646 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
3647 * @priv: pointer to private data registered with IPA (we register a
3648 * pointer to the interface-specific IPA context)
3649 * @evt: the IPA event which triggered the callback
3650 * @data: data associated with the event
3651 *
3652 * Return: None
3653 */
3654static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
3655 unsigned long data)
3656{
3657 cds_ssr_protect(__func__);
3658 __hdd_ipa_i2w_cb(priv, evt, data);
3659 cds_ssr_unprotect(__func__);
3660}
3661
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003662/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003663 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003664 * @hdd_ctx: Global HDD context
3665 *
3666 * Return: 0 on success, negativer errno on error
3667 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003668static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003669{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003670 struct hdd_ipa_priv *hdd_ipa;
3671
3672 if (wlan_hdd_validate_context(hdd_ctx))
3673 return 0;
3674
3675 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003676
3677 if (!hdd_ipa_is_enabled(hdd_ctx))
3678 return 0;
3679
3680 /*
3681 * Check if IPA is ready for suspend, If we are here means, there is
3682 * high chance that suspend would go through but just to avoid any race
3683 * condition after suspend started, these checks are conducted before
3684 * allowing to suspend.
3685 */
3686 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3687 return -EAGAIN;
3688
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303689 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003690
3691 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303692 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003693 return -EAGAIN;
3694 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303695 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003696
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303697 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003698 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303699 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003700
3701 return 0;
3702}
3703
3704/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003705 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
3706 * @hdd_ctx: Global HDD context
3707 *
3708 * Return: 0 on success, negativer errno on error
3709 */
3710int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
3711{
3712 int ret;
3713
3714 cds_ssr_protect(__func__);
3715 ret = __hdd_ipa_suspend(hdd_ctx);
3716 cds_ssr_unprotect(__func__);
3717
3718 return ret;
3719}
3720
3721/**
3722 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003723 * hdd_ctx: Global HDD context
3724 *
3725 * Return: 0 on success, negative errno on error
3726 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003727static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003728{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003729 struct hdd_ipa_priv *hdd_ipa;
3730
3731 if (wlan_hdd_validate_context(hdd_ctx))
3732 return 0;
3733
3734 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003735
3736 if (!hdd_ipa_is_enabled(hdd_ctx))
3737 return 0;
3738
3739 schedule_work(&hdd_ipa->pm_work);
3740
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303741 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003742 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303743 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003744
3745 return 0;
3746}
3747
3748/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003749 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
3750 * hdd_ctx: Global HDD context
3751 *
3752 * Return: 0 on success, negative errno on error
3753 */
3754int hdd_ipa_resume(hdd_context_t *hdd_ctx)
3755{
3756 int ret;
3757
3758 cds_ssr_protect(__func__);
3759 ret = __hdd_ipa_resume(hdd_ctx);
3760 cds_ssr_unprotect(__func__);
3761
3762 return ret;
3763}
3764
3765/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003766 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
3767 * @hdd_ipa: Global HDD IPA context
3768 *
3769 * Return: 0 on success, negative errno on error
3770 */
3771static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
3772{
3773 int i, ret = 0;
3774 struct ipa_sys_connect_params *ipa;
3775 uint32_t desc_fifo_sz;
3776
3777 /* The maximum number of descriptors that can be provided to a BAM at
3778 * once is one less than the total number of descriptors that the buffer
3779 * can contain.
3780 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
3781 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
3782 * be provided at once.
3783 * Because of above requirement, one extra descriptor will be added to
3784 * make sure hardware always has one descriptor.
3785 */
3786 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
3787 + sizeof(struct sps_iovec);
3788
3789 /*setup TX pipes */
3790 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3791 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
3792
3793 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
3794 ipa->desc_fifo_sz = desc_fifo_sz;
3795 ipa->priv = &hdd_ipa->iface_context[i];
3796 ipa->notify = hdd_ipa_i2w_cb;
3797
3798 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
3799 ipa->ipa_ep_cfg.hdr.hdr_len =
3800 HDD_IPA_UC_WLAN_TX_HDR_LEN;
3801 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3802 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
3803 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
3804 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
3805 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
3806 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
3807 } else {
3808 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
3809 }
3810 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
3811
3812 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3813 ipa->keep_ipa_awake = 1;
3814
3815 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
3816 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303817 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003818 " ret: %d", i, ret);
3819 goto setup_sys_pipe_fail;
3820 }
3821 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
3822 }
3823
3824 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
3825 /*
3826 * Hard code it here, this can be extended if in case
3827 * PROD pipe is also per interface.
3828 * Right now there is no advantage of doing this.
3829 */
3830 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
3831
3832 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
3833
3834 ipa->client = hdd_ipa->prod_client;
3835
3836 ipa->desc_fifo_sz = desc_fifo_sz;
3837 ipa->priv = hdd_ipa;
3838 ipa->notify = hdd_ipa_w2i_cb;
3839
3840 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3841 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
3842 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
3843 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
3844
3845 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3846 ipa->keep_ipa_awake = 1;
3847
3848 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
3849 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303850 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003851 "Failed for RX pipe: %d", ret);
3852 goto setup_sys_pipe_fail;
3853 }
3854 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
3855 }
3856
3857 return ret;
3858
3859setup_sys_pipe_fail:
3860
3861 while (--i >= 0) {
3862 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303863 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003864 sizeof(struct hdd_ipa_sys_pipe));
3865 }
3866
3867 return ret;
3868}
3869
3870/**
3871 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
3872 * @hdd_ipa: Global HDD IPA context
3873 *
3874 * Return: None
3875 */
3876static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
3877{
3878 int ret = 0, i;
3879 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
3880 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
3881 ret =
3882 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
3883 conn_hdl);
3884 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303885 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003886 ret);
3887
3888 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
3889 }
3890 }
3891}
3892
3893/**
3894 * hdd_ipa_register_interface() - register IPA interface
3895 * @hdd_ipa: Global IPA context
3896 * @iface_context: Per-interface IPA context
3897 *
3898 * Return: 0 on success, negative errno on error
3899 */
3900static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
3901 struct hdd_ipa_iface_context
3902 *iface_context)
3903{
3904 struct ipa_tx_intf tx_intf;
3905 struct ipa_rx_intf rx_intf;
3906 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
3907 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
3908 char *ifname = iface_context->adapter->dev->name;
3909
3910 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
3911 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
3912
3913 int num_prop = 1;
3914 int ret = 0;
3915
3916 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
3917 num_prop++;
3918
3919 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
3920 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303921 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003922 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303923 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003924 goto register_interface_fail;
3925 }
3926
3927 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
3928 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303929 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003930 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303931 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003932 goto register_interface_fail;
3933 }
3934
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303935 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
3936 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003937
3938 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
3939 ifname, HDD_IPA_IPV4_NAME_EXT);
3940 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
3941 ifname, HDD_IPA_IPV6_NAME_EXT);
3942
3943 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
3944 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
3945 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3946 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
3947
3948 /*
3949 * Interface ID is 3rd byte in the CLD header. Add the meta data and
3950 * mask to identify the interface in IPA hardware
3951 */
3952 rx_prop[IPA_IP_v4].attrib.meta_data =
3953 htonl(iface_context->adapter->sessionId << 16);
3954 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
3955
3956 rx_intf.num_props++;
3957 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3958 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
3959 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
3960 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3961 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
3962 rx_prop[IPA_IP_v4].attrib.meta_data =
3963 htonl(iface_context->adapter->sessionId << 16);
3964 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
3965
3966 rx_intf.num_props++;
3967 }
3968
3969 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
3970 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3971 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
3972 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
3973 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
3974 IPA_RESOURCE_NAME_MAX);
3975 tx_intf.num_props++;
3976
3977 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3978 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
3979 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3980 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
3981 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
3982 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
3983 IPA_RESOURCE_NAME_MAX);
3984 tx_intf.num_props++;
3985 }
3986
3987 tx_intf.prop = tx_prop;
3988 rx_intf.prop = rx_prop;
3989
3990 /* Call the ipa api to register interface */
3991 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
3992
3993register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303994 qdf_mem_free(tx_prop);
3995 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003996 return ret;
3997}
3998
3999/**
4000 * hdd_remove_ipa_header() - Remove a specific header from IPA
4001 * @name: Name of the header to be removed
4002 *
4003 * Return: None
4004 */
4005static void hdd_ipa_remove_header(char *name)
4006{
4007 struct ipa_ioc_get_hdr hdrlookup;
4008 int ret = 0, len;
4009 struct ipa_ioc_del_hdr *ipa_hdr;
4010
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304011 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
4013 ret = ipa_get_hdr(&hdrlookup);
4014 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304015 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004016 name, ret);
4017 return;
4018 }
4019
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304020 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004021 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304022 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004023 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304024 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004025 return;
4026 }
4027 ipa_hdr->num_hdls = 1;
4028 ipa_hdr->commit = 0;
4029 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
4030 ipa_hdr->hdl[0].status = -1;
4031 ret = ipa_del_hdr(ipa_hdr);
4032 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304033 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004034 ret);
4035
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304036 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004037}
4038
4039/**
Yun Parkb187d542016-11-14 18:10:04 -08004040 * wlan_ipa_add_hdr() - Add IPA Tx header
4041 * @ipa_hdr: pointer to IPA header addition parameters
4042 *
4043 * Call IPA API to add IPA Tx header descriptor
4044 * and dump Tx header struct
4045 *
4046 * Return: 0 for success, non-zero for failure
4047 */
4048static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
4049{
4050 int ret;
4051
4052 hdd_info("==== IPA Tx Header ====\n"
4053 "name: %s\n"
4054 "hdr_len: %d\n"
4055 "type: %d\n"
4056 "is_partial: %d\n"
4057 "hdr_hdl: 0x%x\n"
4058 "status: %d\n"
4059 "is_eth2_ofst_valid: %d\n"
4060 "eth2_ofst: %d\n",
4061 ipa_hdr->hdr[0].name,
4062 ipa_hdr->hdr[0].hdr_len,
4063 ipa_hdr->hdr[0].type,
4064 ipa_hdr->hdr[0].is_partial,
4065 ipa_hdr->hdr[0].hdr_hdl,
4066 ipa_hdr->hdr[0].status,
4067 ipa_hdr->hdr[0].is_eth2_ofst_valid,
4068 ipa_hdr->hdr[0].eth2_ofst);
4069
4070 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:",
4071 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4072
4073 ret = ipa_add_hdr(ipa_hdr);
4074 return ret;
4075}
4076
4077/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004078 * hdd_ipa_add_header_info() - Add IPA header for a given interface
4079 * @hdd_ipa: Global HDD IPA context
4080 * @iface_context: Interface-specific HDD IPA context
4081 * @mac_addr: Interface MAC address
4082 *
4083 * Return: 0 on success, negativer errno value on error
4084 */
4085static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
4086 struct hdd_ipa_iface_context *iface_context,
4087 uint8_t *mac_addr)
4088{
4089 hdd_adapter_t *adapter = iface_context->adapter;
4090 char *ifname;
4091 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
4092 int ret = -EINVAL;
4093 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
4094 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
4095
4096 ifname = adapter->dev->name;
4097
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304098 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004099 ifname, mac_addr);
4100
4101 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304102 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004103 + sizeof(struct ipa_hdr_add));
4104 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304105 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004106 "%s: ipa_hdr allocation failed", ifname);
4107 ret = -ENOMEM;
4108 goto end;
4109 }
4110
4111 ipa_hdr->commit = 0;
4112 ipa_hdr->num_hdrs = 1;
4113
4114 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4115 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4116 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4117 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4118 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304119 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004120 "ifname=%s, vdev_id=%d",
4121 ifname, uc_tx_hdr->ipa_hd.vdev_id);
4122 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4123 ifname, HDD_IPA_IPV4_NAME_EXT);
4124 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
4125 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
4126 ipa_hdr->hdr[0].is_partial = 1;
4127 ipa_hdr->hdr[0].hdr_hdl = 0;
4128 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4129 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4130
Yun Parkb187d542016-11-14 18:10:04 -08004131 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004132 } else {
4133 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4134
4135 /* Set the Source MAC */
4136 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
4137 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4138
4139 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4140 ifname, HDD_IPA_IPV4_NAME_EXT);
4141 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4142 ipa_hdr->hdr[0].is_partial = 1;
4143 ipa_hdr->hdr[0].hdr_hdl = 0;
4144 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4145 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4146
4147 /* Set the type to IPV4 in the header */
4148 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
4149
4150 ret = ipa_add_hdr(ipa_hdr);
4151 }
4152 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304153 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004154 ifname, ret);
4155 goto end;
4156 }
4157
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304158 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004159 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4160
4161 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4162 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4163 ifname, HDD_IPA_IPV6_NAME_EXT);
4164
4165 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4166 uc_tx_hdr =
4167 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4168 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004169 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004170 } else {
4171 /* Set the type to IPV6 in the header */
4172 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4173 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004174 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004175 }
4176
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004177 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304178 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004179 "%s: IPv6 add hdr failed: %d", ifname, ret);
4180 goto clean_ipv4_hdr;
4181 }
4182
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304183 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004184 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4185 }
4186
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304187 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004188
4189 return ret;
4190
4191clean_ipv4_hdr:
4192 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4193 ifname, HDD_IPA_IPV4_NAME_EXT);
4194 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
4195end:
4196 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304197 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004198
4199 return ret;
4200}
4201
4202/**
4203 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
4204 * @adapter: Adapter upon which IPA was previously configured
4205 *
4206 * Return: None
4207 */
4208static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
4209{
4210 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4211 int ret;
4212 char name_ipa[IPA_RESOURCE_NAME_MAX];
4213
4214 /* Remove the headers */
4215 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4216 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
4217 hdd_ipa_remove_header(name_ipa);
4218
4219 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4220 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4221 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
4222 hdd_ipa_remove_header(name_ipa);
4223 }
4224 /* unregister the interface with IPA */
4225 ret = ipa_deregister_intf(adapter->dev->name);
4226 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304227 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004228 "%s: ipa_deregister_intf fail: %d",
4229 adapter->dev->name, ret);
4230}
4231
4232/**
4233 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4234 * @iface_context: interface-specific IPA context
4235 *
4236 * Return: None
4237 */
4238static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4239{
4240 if (iface_context == NULL)
4241 return;
4242
4243 hdd_ipa_clean_hdr(iface_context->adapter);
4244
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304245 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004246 iface_context->adapter->ipa_context = NULL;
4247 iface_context->adapter = NULL;
4248 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304249 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004250 iface_context->ifa_address = 0;
4251 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304252 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004253 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304254 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004255 }
4256 iface_context->hdd_ipa->num_iface--;
4257}
4258
4259/**
4260 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4261 * @hdd_ipa: HDD IPA global context
4262 * @adapter: Interface upon which IPA is being setup
4263 * @sta_id: Station ID of the API instance
4264 *
4265 * Return: 0 on success, negative errno value on error
4266 */
4267static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
4268 hdd_adapter_t *adapter, uint8_t sta_id)
4269{
4270 struct hdd_ipa_iface_context *iface_context = NULL;
4271 void *tl_context = NULL;
4272 int i, ret = 0;
4273
4274 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4275 * channel change indication. Since these indications are sent by lower
4276 * layer as SAP updates and IPA doesn't have to do anything for these
4277 * updates so ignoring!
4278 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004279 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 return 0;
4281
4282 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4283 if (hdd_ipa->iface_context[i].adapter == NULL) {
4284 iface_context = &(hdd_ipa->iface_context[i]);
4285 break;
4286 }
4287 }
4288
4289 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304290 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004291 "All the IPA interfaces are in use");
4292 ret = -ENOMEM;
4293 goto end;
4294 }
4295
4296 adapter->ipa_context = iface_context;
4297 iface_context->adapter = adapter;
4298 iface_context->sta_id = sta_id;
Leo Changfdb45c32016-10-28 11:09:23 -07004299 tl_context = cdp_peer_get_vdev_by_sta_id(
4300 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004301 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304302 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004303 "Not able to get TL context sta_id: %d", sta_id);
4304 ret = -EINVAL;
4305 goto end;
4306 }
4307
4308 iface_context->tl_context = tl_context;
4309
4310 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
4311 adapter->dev->dev_addr);
4312
4313 if (ret)
4314 goto end;
4315
4316 /* Configure the TX and RX pipes filter rules */
4317 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
4318 if (ret)
4319 goto cleanup_header;
4320
4321 hdd_ipa->num_iface++;
4322 return ret;
4323
4324cleanup_header:
4325
4326 hdd_ipa_clean_hdr(adapter);
4327end:
4328 if (iface_context)
4329 hdd_ipa_cleanup_iface(iface_context);
4330 return ret;
4331}
4332
Yun Parka27049a2016-10-11 12:30:49 -07004333#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004335 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 * @mcc_mode: 0=MCC/1=SCC
4337 *
4338 * Return: 0 on success, negative errno value on error
4339 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004340static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004341{
4342 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304343 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344 hdd_adapter_t *pAdapter;
4345 struct ipa_msg_meta meta;
4346 struct ipa_wlan_msg *msg;
4347 int ret;
4348
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004349 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004350 return -EINVAL;
4351
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004352 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4353 return -EINVAL;
4354
4355 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004356 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004357 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304358 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004359 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08004360 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004361 pAdapter->device_mode == QDF_SAP_MODE) {
4362 hdd_info("MCC->SCC: Flush TxRx queue(d_mode=%d)",
4363 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004364 hdd_deinit_tx_rx(pAdapter);
4365 }
4366 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004367 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004368 adapter_node = next;
4369 }
4370 }
4371
4372 /* Send SCC/MCC Switching event to IPA */
4373 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304374 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004375 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004376 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004377 return -ENOMEM;
4378 }
4379
4380 meta.msg_type = mcc_mode ?
4381 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004382 hdd_info("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004383
4384 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4385
4386 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004387 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004388 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304389 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004390 }
4391
4392 return ret;
4393}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004394
4395/**
4396 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4397 * @mcc_mode: 0=MCC/1=SCC
4398 *
4399 * Return: 0 on success, negative errno value on error
4400 */
4401int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
4402{
4403 int ret;
4404
4405 cds_ssr_protect(__func__);
4406 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4407 cds_ssr_unprotect(__func__);
4408
4409 return ret;
4410}
Yun Parka27049a2016-10-11 12:30:49 -07004411#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004412
4413/**
4414 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4415 * @event: IPA WLAN event to be converted to a string
4416 *
4417 * Return: ASCII string representing the IPA WLAN event
4418 */
4419static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4420{
4421 switch (event) {
4422 case WLAN_CLIENT_CONNECT:
4423 return "WLAN_CLIENT_CONNECT";
4424 case WLAN_CLIENT_DISCONNECT:
4425 return "WLAN_CLIENT_DISCONNECT";
4426 case WLAN_CLIENT_POWER_SAVE_MODE:
4427 return "WLAN_CLIENT_POWER_SAVE_MODE";
4428 case WLAN_CLIENT_NORMAL_MODE:
4429 return "WLAN_CLIENT_NORMAL_MODE";
4430 case SW_ROUTING_ENABLE:
4431 return "SW_ROUTING_ENABLE";
4432 case SW_ROUTING_DISABLE:
4433 return "SW_ROUTING_DISABLE";
4434 case WLAN_AP_CONNECT:
4435 return "WLAN_AP_CONNECT";
4436 case WLAN_AP_DISCONNECT:
4437 return "WLAN_AP_DISCONNECT";
4438 case WLAN_STA_CONNECT:
4439 return "WLAN_STA_CONNECT";
4440 case WLAN_STA_DISCONNECT:
4441 return "WLAN_STA_DISCONNECT";
4442 case WLAN_CLIENT_CONNECT_EX:
4443 return "WLAN_CLIENT_CONNECT_EX";
4444
4445 case IPA_WLAN_EVENT_MAX:
4446 default:
4447 return "UNKNOWN";
4448 }
4449}
4450
4451/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004452 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4453 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4454 *
4455 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4456 */
4457static enum ipa_wlan_event
4458hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4459{
4460 enum ipa_wlan_event ipa_event;
4461
4462 switch (hdd_ipa_event_type) {
4463 case HDD_IPA_CLIENT_CONNECT:
4464 ipa_event = WLAN_CLIENT_CONNECT;
4465 break;
4466 case HDD_IPA_CLIENT_DISCONNECT:
4467 ipa_event = WLAN_CLIENT_DISCONNECT;
4468 break;
4469 case HDD_IPA_AP_CONNECT:
4470 ipa_event = WLAN_AP_CONNECT;
4471 break;
4472 case HDD_IPA_AP_DISCONNECT:
4473 ipa_event = WLAN_AP_DISCONNECT;
4474 break;
4475 case HDD_IPA_STA_CONNECT:
4476 ipa_event = WLAN_STA_CONNECT;
4477 break;
4478 case HDD_IPA_STA_DISCONNECT:
4479 ipa_event = WLAN_STA_DISCONNECT;
4480 break;
4481 case HDD_IPA_CLIENT_CONNECT_EX:
4482 ipa_event = WLAN_CLIENT_CONNECT_EX;
4483 break;
4484 case HDD_IPA_WLAN_EVENT_MAX:
4485 default:
4486 ipa_event = IPA_WLAN_EVENT_MAX;
4487 break;
4488 }
4489 return ipa_event;
4490
4491}
4492
4493/**
4494 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004495 * @adapter: adapter upon which the event was received
4496 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004497 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498 * @mac_address: MAC address associated with the event
4499 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004500 * This function is meant to be called from within wlan_hdd_ipa.c
4501 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502 * Return: 0 on success, negative errno value on error
4503 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07004504static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004505 enum ipa_wlan_event type, uint8_t *mac_addr)
4506{
4507 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4508 struct ipa_msg_meta meta;
4509 struct ipa_wlan_msg *msg;
4510 struct ipa_wlan_msg_ex *msg_ex = NULL;
4511 int ret;
4512
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304513 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004514 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
4515 mac_addr, sta_id);
4516
4517 if (type >= IPA_WLAN_EVENT_MAX)
4518 return -EINVAL;
4519
4520 if (WARN_ON(is_zero_ether_addr(mac_addr)))
4521 return -EINVAL;
4522
4523 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304524 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004525 return -EINVAL;
4526 }
4527
4528 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
4529 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08004530 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004531 return 0;
4532 }
4533
4534 /*
4535 * During IPA UC resource loading/unloading new events can be issued.
4536 * Store the events separately and handle them later.
4537 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004538 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4539 if (hdd_ipa->resource_loading) {
4540 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004541 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08004542
Yun Park7c4f31b2016-11-30 10:09:21 -08004543 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA resource %s inprogress",
4544 hdd_ipa->resource_loading ? "load":"unload");
4545
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004546 hdd_err("IPA resource %s inprogress",
4547 hdd_ipa->resource_loading ? "load":"unload");
Yun Parkf19e07d2015-11-20 11:34:27 -08004548
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004549 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004550
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004551 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4552 if (pending_event_count >= HDD_IPA_MAX_PENDING_EVENT_COUNT) {
4553 hdd_notice("Reached max pending event count");
4554 qdf_list_remove_front(&hdd_ipa->pending_event,
4555 (qdf_list_node_t **)&pending_event);
4556 } else {
4557 pending_event =
4558 (struct ipa_uc_pending_event *)qdf_mem_malloc(
4559 sizeof(struct ipa_uc_pending_event));
4560 }
4561
4562 if (!pending_event) {
Yun Park7c4f31b2016-11-30 10:09:21 -08004563 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4564 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004565 qdf_mutex_release(&hdd_ipa->event_lock);
4566 return -ENOMEM;
4567 }
4568
4569 pending_event->adapter = adapter;
4570 pending_event->sta_id = sta_id;
4571 pending_event->type = type;
4572 qdf_mem_copy(pending_event->mac_addr,
4573 mac_addr,
4574 QDF_MAC_ADDR_SIZE);
4575 qdf_list_insert_back(&hdd_ipa->pending_event,
4576 &pending_event->node);
4577
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304578 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004579 return 0;
4580 } else if (hdd_ipa->resource_unloading) {
4581 hdd_err("%s: IPA resource unload inprogress", __func__);
4582 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004583 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004584 }
4585
4586 hdd_ipa->stats.event[type]++;
4587
Leo Chang3bc8fed2015-11-13 10:59:47 -08004588 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004589 switch (type) {
4590 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004591 qdf_mutex_acquire(&hdd_ipa->event_lock);
4592
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004593 /* STA already connected and without disconnect, connect again
4594 * This is Roaming scenario
4595 */
4596 if (hdd_ipa->sta_connected)
4597 hdd_ipa_cleanup_iface(adapter->ipa_context);
4598
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004599 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4600 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304601 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004602 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004603 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004604
Yun Park8f289c82016-10-18 16:38:21 -07004605 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4606 (hdd_ipa->sap_num_connected_sta > 0) &&
4607 !hdd_ipa->sta_connected) {
4608 qdf_mutex_release(&hdd_ipa->event_lock);
4609 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004610 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004611 qdf_mutex_acquire(&hdd_ipa->event_lock);
4612 }
4613
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004614 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004616 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004617
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004618 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07004619
4620 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004621 break;
4622
4623 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004624 qdf_mutex_acquire(&hdd_ipa->event_lock);
4625
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004626 /* For DFS channel we get two start_bss event (before and after
4627 * CAC). Also when ACS range includes both DFS and non DFS
4628 * channels, we could possibly change channel many times due to
4629 * RADAR detection and chosen channel may not be a DFS channels.
4630 * So dont return error here. Just discard the event.
4631 */
Yun Park8f289c82016-10-18 16:38:21 -07004632 if (adapter->ipa_context) {
4633 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07004635 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004636
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4638 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004639 hdd_err("%s: Evt: %d, Interface setup failed",
4640 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304641 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004642 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004643 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644
Yun Park8f289c82016-10-18 16:38:21 -07004645 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4646 qdf_mutex_release(&hdd_ipa->event_lock);
4647 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004648 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004649 qdf_mutex_acquire(&hdd_ipa->event_lock);
4650 }
4651
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004652 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004653 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004654 (adapter->ipa_context))->iface_id;
4655
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304656 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004657 break;
4658
4659 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304660 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004661
4662 if (!hdd_ipa->sta_connected) {
Yun Parkb187d542016-11-14 18:10:04 -08004663 hdd_err("%s: Evt: %d, STA already disconnected",
4664 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304665 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004666 return -EINVAL;
4667 }
Yun Parka37592b2016-06-11 17:10:28 -07004668
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07004670
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004671 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08004672 hdd_notice("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004673 msg_ex->name);
4674 } else {
4675 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07004676 if (!hdd_ipa->num_iface &&
4677 (HDD_IPA_UC_NUM_WDI_PIPE ==
4678 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004679 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004680 }
4681
Yun Park74127cf2016-09-18 11:22:41 -07004682 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4683 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07004684 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004685 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004686 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004687 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004688 hdd_ipa->vdev_to_iface[adapter->sessionId] =
4689 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004690 }
4691
Yun Park8f289c82016-10-18 16:38:21 -07004692 hdd_ipa_cleanup_iface(adapter->ipa_context);
4693
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304694 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004695 break;
4696
4697 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004698 qdf_mutex_acquire(&hdd_ipa->event_lock);
4699
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004700 if (!adapter->ipa_context) {
Yun Parkb187d542016-11-14 18:10:04 -08004701 hdd_err("%s: Evt: %d, SAP already disconnected",
4702 msg_ex->name, meta.msg_type);
Yun Park8f289c82016-10-18 16:38:21 -07004703 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004704 return -EINVAL;
4705 }
4706
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707 if ((!hdd_ipa->num_iface) &&
4708 (HDD_IPA_UC_NUM_WDI_PIPE ==
4709 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004710 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004711 /*
4712 * We disable WDI pipes directly here since
4713 * IPA_OPCODE_TX/RX_SUSPEND message will not be
4714 * processed when unloading WLAN driver is in
4715 * progress
4716 */
4717 hdd_ipa_uc_disable_pipes(hdd_ipa);
4718 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304719 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004720 "NO INTF left but still pipe clean up");
4721 hdd_ipa_uc_handle_last_discon(hdd_ipa);
4722 }
4723 }
4724
4725 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07004726 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004727 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004728 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004729 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004730 hdd_ipa->vdev_to_iface[adapter->sessionId] =
4731 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004732 }
Yun Parka37592b2016-06-11 17:10:28 -07004733
Yun Park8f289c82016-10-18 16:38:21 -07004734 hdd_ipa_cleanup_iface(adapter->ipa_context);
4735
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304736 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004737 break;
4738
4739 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004740 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304741 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004742 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304743 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004744 return 0;
4745 }
4746
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304747 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004748 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
4749 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07004750 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304751 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004752 "%s: STA ID %d found, not valid",
4753 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004754 return 0;
4755 }
Yun Park312f71a2015-12-08 10:22:42 -08004756
4757 /* Enable IPA UC Data PIPEs when first STA connected */
Yun Parka37592b2016-06-11 17:10:28 -07004758 if (0 == hdd_ipa->sap_num_connected_sta) {
4759 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07004760 hdd_ipa->sta_connected) {
4761 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07004762 hdd_ipa_uc_offload_enable_disable(
4763 hdd_get_adapter(hdd_ipa->hdd_ctx,
4764 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004765 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004766 qdf_mutex_acquire(&hdd_ipa->event_lock);
4767 }
Yun Parka37592b2016-06-11 17:10:28 -07004768
Yun Park312f71a2015-12-08 10:22:42 -08004769 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
4770 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304771 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08004772 "%s: handle 1st con ret %d",
4773 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07004774
4775 if (hdd_ipa_uc_sta_is_enabled(
4776 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07004777 hdd_ipa->sta_connected) {
4778 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07004779 hdd_ipa_uc_offload_enable_disable(
4780 hdd_get_adapter(
4781 hdd_ipa->hdd_ctx,
4782 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004783 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004784 } else {
4785 qdf_mutex_release(&hdd_ipa->event_lock);
4786 }
Yun Parka37592b2016-06-11 17:10:28 -07004787
Yun Park312f71a2015-12-08 10:22:42 -08004788 return ret;
4789 }
4790 }
4791
4792 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08004793
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304794 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004795
4796 meta.msg_type = type;
4797 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
4798 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304799 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004800
4801 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304802 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004803 "msg_ex allocation failed");
4804 return -ENOMEM;
4805 }
4806 strlcpy(msg_ex->name, adapter->dev->name,
4807 IPA_RESOURCE_NAME_MAX);
4808 msg_ex->num_of_attribs = 1;
4809 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
4810 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4811 msg_ex->attribs[0].offset =
4812 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4813 } else {
4814 msg_ex->attribs[0].offset =
4815 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4816 }
4817 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
4818 IPA_MAC_ADDR_SIZE);
4819
4820 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
4821
4822 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304823 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304824 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304825 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004826 return ret;
4827 }
4828 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004829 return ret;
4830
4831 case WLAN_CLIENT_DISCONNECT:
4832 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304833 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004834 "%s: IPA UC OFFLOAD NOT ENABLED",
4835 msg_ex->name);
4836 return 0;
4837 }
4838
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304839 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004840 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304841 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004842 "%s: STA ID %d NOT found, not valid",
4843 msg_ex->name, sta_id);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304844 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004845 return 0;
4846 }
4847 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07004848
Yun Park9b5030f2016-11-08 12:02:37 -08004849 /* Disable IPA UC TX PIPE when last STA disconnected */
4850 if (!hdd_ipa->sap_num_connected_sta) {
4851 if ((false == hdd_ipa->resource_unloading)
4852 && (HDD_IPA_UC_NUM_WDI_PIPE ==
4853 hdd_ipa->activated_fw_pipe)) {
4854 hdd_ipa_uc_handle_last_discon(hdd_ipa);
4855 }
4856
Yun Park8f289c82016-10-18 16:38:21 -07004857 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08004858
4859 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4860 hdd_ipa->sta_connected)
4861 hdd_ipa_uc_offload_enable_disable(
4862 hdd_get_adapter(hdd_ipa->hdd_ctx,
4863 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004864 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004865 } else {
4866 qdf_mutex_release(&hdd_ipa->event_lock);
4867 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004868 break;
4869
4870 default:
4871 return 0;
4872 }
4873
4874 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304875 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004876 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304877 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004878 return -ENOMEM;
4879 }
4880
4881 meta.msg_type = type;
4882 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
4883 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
4884
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304885 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004886 msg->name, meta.msg_type);
4887
4888 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4889
4890 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004891 hdd_err("%s: Evt: %d fail:%d",
4892 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304893 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004894 return ret;
4895 }
4896
4897 hdd_ipa->stats.num_send_msg++;
4898
4899end:
4900 return ret;
4901}
4902
4903/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004904 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07004905 * @adapter: adapter upon which the event was received
4906 * @sta_id: station id for the event
4907 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
4908 * @mac_address: MAC address associated with the event
4909 *
4910 * This function is meant to be called from outside of wlan_hdd_ipa.c.
4911 *
4912 * Return: 0 on success, negative errno value on error
4913 */
4914int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
4915 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
4916{
4917 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004918 int ret = 0;
4919
4920 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07004921
Leo Changa202b522016-10-14 16:13:50 -07004922 /* Data path offload only support for STA and SAP mode */
4923 if ((QDF_STA_MODE == adapter->device_mode) ||
4924 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004925 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07004926
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004927 cds_ssr_unprotect(__func__);
4928
4929 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07004930}
4931
4932/**
4933 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
4934 * @hdd_ipa: Global HDD IPA context
4935 *
4936 * Return: None
4937 */
4938static void
4939hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
4940{
4941 unsigned int pending_event_count;
4942 struct ipa_uc_pending_event *pending_event = NULL;
4943
4944 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4945 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4946 "%s, Pending Event Count %d", __func__, pending_event_count);
4947 if (!pending_event_count) {
4948 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4949 "%s, No Pending Event", __func__);
4950 return;
4951 }
4952
4953 qdf_list_remove_front(&hdd_ipa->pending_event,
4954 (qdf_list_node_t **)&pending_event);
4955 while (pending_event != NULL) {
4956 __hdd_ipa_wlan_evt(pending_event->adapter,
4957 pending_event->type,
4958 pending_event->sta_id,
4959 pending_event->mac_addr);
4960 qdf_mem_free(pending_event);
4961 pending_event = NULL;
4962 qdf_list_remove_front(&hdd_ipa->pending_event,
4963 (qdf_list_node_t **)&pending_event);
4964 }
4965}
4966
4967/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004968 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
4969 * @state: IPA RM state value
4970 *
4971 * Return: ASCII string representing the IPA RM state
4972 */
4973static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
4974{
4975 switch (state) {
4976 case HDD_IPA_RM_RELEASED:
4977 return "RELEASED";
4978 case HDD_IPA_RM_GRANT_PENDING:
4979 return "GRANT_PENDING";
4980 case HDD_IPA_RM_GRANTED:
4981 return "GRANTED";
4982 }
4983
4984 return "UNKNOWN";
4985}
4986
4987/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004988 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004989 * @hdd_ctx: HDD global context
4990 *
4991 * Allocate hdd_ipa resources, ipa pipe resource and register
4992 * wlan interface with IPA module.
4993 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304994 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004995 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004996static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004997{
4998 struct hdd_ipa_priv *hdd_ipa = NULL;
4999 int ret, i;
5000 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park7f171ab2016-07-29 15:44:22 -07005001 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005002
5003 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305004 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005005
Yun Park7f171ab2016-07-29 15:44:22 -07005006 if (!pdev) {
5007 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5008 goto fail_return;
5009 }
5010
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305011 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005012 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305013 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005014 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005015 }
5016
5017 hdd_ctx->hdd_ipa = hdd_ipa;
5018 ghdd_ipa = hdd_ipa;
5019 hdd_ipa->hdd_ctx = hdd_ctx;
5020 hdd_ipa->num_iface = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07005021 cdp_ipa_get_resource(cds_get_context(QDF_MODULE_ID_SOC),
5022 cds_get_context(QDF_MODULE_ID_TXRX),
5023 &hdd_ipa->ipa_resource);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08005024 if ((0 == hdd_ipa->ipa_resource.ce_sr_base_paddr) ||
5025 (0 == hdd_ipa->ipa_resource.tx_comp_ring_base_paddr) ||
5026 (0 == hdd_ipa->ipa_resource.rx_rdy_ring_base_paddr) ||
5027 (0 == hdd_ipa->ipa_resource.rx2_rdy_ring_base_paddr)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305028 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Leo Chang3bc8fed2015-11-13 10:59:47 -08005029 "IPA UC resource alloc fail");
5030 goto fail_get_resource;
5031 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005032
5033 /* Create the interface context */
5034 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5035 iface_context = &hdd_ipa->iface_context[i];
5036 iface_context->hdd_ipa = hdd_ipa;
5037 iface_context->cons_client =
5038 hdd_ipa_adapter_2_client[i].cons_client;
5039 iface_context->prod_client =
5040 hdd_ipa_adapter_2_client[i].prod_client;
5041 iface_context->iface_id = i;
5042 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305043 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005044 }
5045 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005046 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5047 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005048 }
5049
Leo Chang69c39692016-10-12 20:11:12 -07005050 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305051 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305052 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005053
5054 ret = hdd_ipa_setup_rm(hdd_ipa);
5055 if (ret)
5056 goto fail_setup_rm;
5057
5058 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5059 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305060 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005061 hdd_ipa->sap_num_connected_sta = 0;
5062 hdd_ipa->ipa_tx_packets_diff = 0;
5063 hdd_ipa->ipa_rx_packets_diff = 0;
5064 hdd_ipa->ipa_p_tx_packets = 0;
5065 hdd_ipa->ipa_p_rx_packets = 0;
5066 hdd_ipa->resource_loading = false;
5067 hdd_ipa->resource_unloading = false;
5068 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005069 hdd_ipa->ipa_pipes_down = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005070 /* Setup IPA sys_pipe for MCC */
5071 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5072 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5073 if (ret)
5074 goto fail_create_sys_pipe;
5075 }
5076 hdd_ipa_uc_ol_init(hdd_ctx);
5077 } else {
5078 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5079 if (ret)
5080 goto fail_create_sys_pipe;
5081 }
5082
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305083 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005084
5085fail_create_sys_pipe:
5086 hdd_ipa_destroy_rm_resource(hdd_ipa);
5087fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305088 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005089fail_get_resource:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305090 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005091 hdd_ctx->hdd_ipa = NULL;
5092 ghdd_ipa = NULL;
5093fail_return:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305094 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005095}
5096
5097/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005098 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5099 * @hdd_ctx: HDD global context
5100 *
5101 * Allocate hdd_ipa resources, ipa pipe resource and register
5102 * wlan interface with IPA module.
5103 *
5104 * Return: QDF_STATUS enumeration
5105 */
5106QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
5107{
5108 QDF_STATUS ret;
5109
5110 cds_ssr_protect(__func__);
5111 ret = __hdd_ipa_init(hdd_ctx);
5112 cds_ssr_unprotect(__func__);
5113
5114 return ret;
5115}
5116
5117/**
Yun Parkf19e07d2015-11-20 11:34:27 -08005118 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
5119 * @hdd_ipa: pointer to HDD IPA struct
5120 *
5121 * Return: none
5122 */
Jeff Johnsond7720632016-10-05 16:04:32 -07005123static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08005124{
5125 struct ipa_uc_pending_event *pending_event = NULL;
5126
Anurag Chouhanffb21542016-02-17 14:33:03 +05305127 while (qdf_list_remove_front(&hdd_ipa->pending_event,
5128 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305129 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005130 }
5131
Anurag Chouhanffb21542016-02-17 14:33:03 +05305132 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005133}
5134
5135/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005136 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005137 * @hdd_ctx: HDD global context
5138 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305139 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005140 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005141static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005142{
5143 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5144 int i;
5145 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305146 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005147 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5148
5149 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305150 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005151
5152 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5153 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5154 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5155 }
5156
5157 /* Teardown IPA sys_pipe for MCC */
5158 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5159 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5160
5161 hdd_ipa_destroy_rm_resource(hdd_ipa);
5162
5163#ifdef WLAN_OPEN_SOURCE
5164 cancel_work_sync(&hdd_ipa->pm_work);
5165#endif
5166
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305167 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005168
Nirav Shahcbc6d722016-03-01 16:24:53 +05305169 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5170 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305171 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005172
5173 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
5174 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
5175
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305176 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005177 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305178 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005179
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305180 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005181
5182 /* destory the interface lock */
5183 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5184 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305185 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005186 }
5187
5188 /* This should never hit but still make sure that there are no pending
5189 * descriptor in IPA hardware
5190 */
5191 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305192 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005193 "IPA Pending write done: %d Waiting!",
5194 hdd_ipa->pending_hw_desc_cnt);
5195
5196 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
5197 usleep_range(100, 100);
5198 }
5199
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305200 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005201 "IPA Pending write done: desc: %d %s(%d)!",
5202 hdd_ipa->pending_hw_desc_cnt,
5203 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
5204 : "leak", i);
5205 }
5206 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
5207 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305208 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305209 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
5210 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005211 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305212 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305213 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
5214 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005215 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305216 qdf_mutex_destroy(&hdd_ipa->event_lock);
5217 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005218 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005219
5220#ifdef WLAN_OPEN_SOURCE
5221 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5222 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5223 hdd_ipa->uc_op_work[i].msg = NULL;
5224 }
5225#endif
5226 }
5227
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305228 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005229 hdd_ctx->hdd_ipa = NULL;
5230
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305231 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005232}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005233
5234/**
5235 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5236 * @hdd_ctx: HDD global context
5237 *
5238 * Return: QDF_STATUS enumeration
5239 */
5240QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
5241{
5242 QDF_STATUS ret;
5243
5244 cds_ssr_protect(__func__);
5245 ret = __hdd_ipa_cleanup(hdd_ctx);
5246 cds_ssr_unprotect(__func__);
5247
5248 return ret;
5249}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005250#endif /* IPA_OFFLOAD */