blob: 4f9dbd319270820c5e4124fa1eb63e8bffcb44a2 [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>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070051#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080052
53#include "cds_sched.h"
54
55#include "wma.h"
56#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080057#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080058
Dhanashri Atreb08959a2016-03-01 17:28:03 -080059#include "cdp_txrx_ipa.h"
60
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080061#define HDD_IPA_DESC_BUFFER_RATIO 4
62#define HDD_IPA_IPV4_NAME_EXT "_ipv4"
63#define HDD_IPA_IPV6_NAME_EXT "_ipv6"
64
65#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080066#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
67/* WDI TX and RX PIPE */
68#define HDD_IPA_UC_NUM_WDI_PIPE 2
69#define HDD_IPA_UC_MAX_PENDING_EVENT 33
70
71#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
72#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
73#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
74#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
75
76#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
77#define HDD_IPA_MAX_IFACE 3
78#define HDD_IPA_MAX_SYSBAM_PIPE 4
79#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
80#define HDD_IPA_ENABLE_MASK BIT(0)
81#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
82#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
83#define HDD_IPA_RM_ENABLE_MASK BIT(3)
84#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
85#define HDD_IPA_UC_ENABLE_MASK BIT(5)
86#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
87#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
88
Yun Parkf19e07d2015-11-20 11:34:27 -080089#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
90
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080091typedef enum {
92 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
93 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
94 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
95 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
96 HDD_IPA_UC_OPCODE_STATS = 4,
97 /* keep this last */
98 HDD_IPA_UC_OPCODE_MAX
99} hdd_ipa_uc_op_code;
100
101/**
102 * enum - Reason codes for stat query
103 *
104 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
105 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
106 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800107 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800108 */
109enum {
110 HDD_IPA_UC_STAT_REASON_NONE,
111 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -0800112 HDD_IPA_UC_STAT_REASON_BW_CAL,
113 HDD_IPA_UC_STAT_REASON_DUMP_INFO
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800114};
115
116/**
117 * enum hdd_ipa_rm_state - IPA resource manager state
118 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
119 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
120 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
121 */
122enum hdd_ipa_rm_state {
123 HDD_IPA_RM_RELEASED,
124 HDD_IPA_RM_GRANT_PENDING,
125 HDD_IPA_RM_GRANTED,
126};
127
128struct llc_snap_hdr {
129 uint8_t dsap;
130 uint8_t ssap;
131 uint8_t resv[4];
132 __be16 eth_type;
133} __packed;
134
Leo Chang3bc8fed2015-11-13 10:59:47 -0800135/**
136 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
137 * @eth: ether II header
138 * @llc_snap: LLC snap header
139 *
140 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800141struct hdd_ipa_tx_hdr {
142 struct ethhdr eth;
143 struct llc_snap_hdr llc_snap;
144} __packed;
145
Leo Chang3bc8fed2015-11-13 10:59:47 -0800146/**
147 * struct frag_header - fragment header type registered to IPA hardware
148 * @length: fragment length
149 * @reserved1: Reserved not used
150 * @reserved2: Reserved not used
151 *
152 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800153struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800154 uint16_t length;
155 uint32_t reserved1;
156 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800157} __packed;
158
Leo Chang3bc8fed2015-11-13 10:59:47 -0800159/**
160 * struct ipa_header - ipa header type registered to IPA hardware
161 * @vdev_id: vdev id
162 * @reserved: Reserved not used
163 *
164 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165struct ipa_header {
166 uint32_t
167 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
168 reserved:24;
169} __packed;
170
Leo Chang3bc8fed2015-11-13 10:59:47 -0800171/**
172 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
173 * @frag_hd: fragment header
174 * @ipa_hd: ipa header
175 * @eth: ether II header
176 *
177 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800178struct hdd_ipa_uc_tx_hdr {
179 struct frag_header frag_hd;
180 struct ipa_header ipa_hd;
181 struct ethhdr eth;
182} __packed;
183
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184/**
185 * struct hdd_ipa_cld_hdr - IPA CLD Header
186 * @reserved: reserved fields
187 * @iface_id: interface ID
188 * @sta_id: Station ID
189 *
190 * Packed 32-bit structure
191 * +----------+----------+--------------+--------+
192 * | Reserved | QCMAP ID | interface id | STA ID |
193 * +----------+----------+--------------+--------+
194 */
195struct hdd_ipa_cld_hdr {
196 uint8_t reserved[2];
197 uint8_t iface_id;
198 uint8_t sta_id;
199} __packed;
200
201struct hdd_ipa_rx_hdr {
202 struct hdd_ipa_cld_hdr cld_hdr;
203 struct ethhdr eth;
204} __packed;
205
206struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700207 bool exception;
208 hdd_adapter_t *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800209 struct hdd_ipa_iface_context *iface_context;
210 struct ipa_rx_data *ipa_tx_desc;
211};
212
213struct hdd_ipa_uc_rx_hdr {
214 struct ethhdr eth;
215} __packed;
216
217struct hdd_ipa_sys_pipe {
218 uint32_t conn_hdl;
219 uint8_t conn_hdl_valid;
220 struct ipa_sys_connect_params ipa_sys_params;
221};
222
223struct hdd_ipa_iface_stats {
224 uint64_t num_tx;
225 uint64_t num_tx_drop;
226 uint64_t num_tx_err;
227 uint64_t num_tx_cac_drop;
228 uint64_t num_rx_prefilter;
229 uint64_t num_rx_ipa_excep;
230 uint64_t num_rx_recv;
231 uint64_t num_rx_recv_mul;
232 uint64_t num_rx_send_desc_err;
233 uint64_t max_rx_mul;
234};
235
236struct hdd_ipa_priv;
237
238struct hdd_ipa_iface_context {
239 struct hdd_ipa_priv *hdd_ipa;
240 hdd_adapter_t *adapter;
241 void *tl_context;
242
243 enum ipa_client_type cons_client;
244 enum ipa_client_type prod_client;
245
246 uint8_t iface_id; /* This iface ID */
247 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530248 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800249 uint32_t ifa_address;
250 struct hdd_ipa_iface_stats stats;
251};
252
253struct hdd_ipa_stats {
254 uint32_t event[IPA_WLAN_EVENT_MAX];
255 uint64_t num_send_msg;
256 uint64_t num_free_msg;
257
258 uint64_t num_rm_grant;
259 uint64_t num_rm_release;
260 uint64_t num_rm_grant_imm;
261 uint64_t num_cons_perf_req;
262 uint64_t num_prod_perf_req;
263
264 uint64_t num_rx_drop;
265 uint64_t num_rx_ipa_tx_dp;
266 uint64_t num_rx_ipa_splice;
267 uint64_t num_rx_ipa_loop;
268 uint64_t num_rx_ipa_tx_dp_err;
269 uint64_t num_rx_ipa_write_done;
270 uint64_t num_max_ipa_tx_mul;
271 uint64_t num_rx_ipa_hw_maxed_out;
272 uint64_t max_pend_q_cnt;
273
274 uint64_t num_tx_comp_cnt;
275 uint64_t num_tx_queued;
276 uint64_t num_tx_dequeued;
277 uint64_t num_max_pm_queue;
278
279 uint64_t num_freeq_empty;
280 uint64_t num_pri_freeq_empty;
281 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800282 uint64_t num_tx_fwd_ok;
283 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800284};
285
286struct ipa_uc_stas_map {
287 bool is_reserved;
288 uint8_t sta_id;
289};
290struct op_msg_type {
291 uint8_t msg_t;
292 uint8_t rsvd;
293 uint16_t op_code;
294 uint16_t len;
295 uint16_t rsvd_snd;
296};
297
298struct ipa_uc_fw_stats {
299 uint32_t tx_comp_ring_base;
300 uint32_t tx_comp_ring_size;
301 uint32_t tx_comp_ring_dbell_addr;
302 uint32_t tx_comp_ring_dbell_ind_val;
303 uint32_t tx_comp_ring_dbell_cached_val;
304 uint32_t tx_pkts_enqueued;
305 uint32_t tx_pkts_completed;
306 uint32_t tx_is_suspend;
307 uint32_t tx_reserved;
308 uint32_t rx_ind_ring_base;
309 uint32_t rx_ind_ring_size;
310 uint32_t rx_ind_ring_dbell_addr;
311 uint32_t rx_ind_ring_dbell_ind_val;
312 uint32_t rx_ind_ring_dbell_ind_cached_val;
313 uint32_t rx_ind_ring_rdidx_addr;
314 uint32_t rx_ind_ring_rd_idx_cached_val;
315 uint32_t rx_refill_idx;
316 uint32_t rx_num_pkts_indicated;
317 uint32_t rx_buf_refilled;
318 uint32_t rx_num_ind_drop_no_space;
319 uint32_t rx_num_ind_drop_no_buf;
320 uint32_t rx_is_suspend;
321 uint32_t rx_reserved;
322};
323
324struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530325 qdf_list_node_t node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800326 hdd_adapter_t *adapter;
327 enum ipa_wlan_event type;
328 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530329 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800330};
331
332/**
333 * struct uc_rm_work_struct
334 * @work: uC RM work
335 * @event: IPA RM event
336 */
337struct uc_rm_work_struct {
338 struct work_struct work;
339 enum ipa_rm_event event;
340};
341
342/**
343 * struct uc_op_work_struct
344 * @work: uC OP work
345 * @msg: OP message
346 */
347struct uc_op_work_struct {
348 struct work_struct work;
349 struct op_msg_type *msg;
350};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800351
352/**
353 * struct uc_rt_debug_info
354 * @time: system time
355 * @ipa_excep_count: IPA exception packet count
356 * @rx_drop_count: IPA Rx drop packet count
357 * @net_sent_count: IPA Rx packet sent to network stack count
358 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800359 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800360 * @tx_fwd_count: IPA Tx forward packet count
361 * @rx_destructor_call: IPA Rx packet destructor count
362 */
363struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530364 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800365 uint64_t ipa_excep_count;
366 uint64_t rx_drop_count;
367 uint64_t net_sent_count;
368 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800369 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370 uint64_t tx_fwd_count;
371 uint64_t rx_destructor_call;
372};
373
374struct hdd_ipa_priv {
375 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
376 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
377 uint8_t num_iface;
378 enum hdd_ipa_rm_state rm_state;
379 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530380 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800381 * APIs as it is taken care gracefully. Without this, kernel would throw
382 * an warning if spin_lock_bh is used while IRQ is disabled
383 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530384 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800385 struct uc_rm_work_struct uc_rm_work;
386 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530387 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800388 struct delayed_work wake_lock_work;
389 bool wake_lock_released;
390
391 enum ipa_client_type prod_client;
392
393 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530394 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800395 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530396 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800397 bool suspended;
398
399 uint32_t pending_hw_desc_cnt;
400 uint32_t hw_desc_cnt;
401 spinlock_t q_lock;
402 uint32_t freeq_cnt;
403 struct list_head free_desc_head;
404
405 uint32_t pend_q_cnt;
406 struct list_head pend_desc_head;
407
408 hdd_context_t *hdd_ctx;
409
410 struct dentry *debugfs_dir;
411 struct hdd_ipa_stats stats;
412
413 struct notifier_block ipv4_notifier;
414 uint32_t curr_prod_bw;
415 uint32_t curr_cons_bw;
416
417 uint8_t activated_fw_pipe;
418 uint8_t sap_num_connected_sta;
419 uint8_t sta_connected;
420 uint32_t tx_pipe_handle;
421 uint32_t rx_pipe_handle;
422 bool resource_loading;
423 bool resource_unloading;
424 bool pending_cons_req;
425 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530426 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530427 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700428 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800429 uint32_t ipa_tx_packets_diff;
430 uint32_t ipa_rx_packets_diff;
431 uint32_t ipa_p_tx_packets;
432 uint32_t ipa_p_rx_packets;
433 uint32_t stat_req_reason;
434 uint64_t ipa_tx_forward;
435 uint64_t ipa_rx_discard;
436 uint64_t ipa_rx_net_send_count;
437 uint64_t ipa_rx_internel_drop_count;
438 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530439 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800440 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
441 unsigned int rt_buf_fill_index;
Anurag Chouhan210db072016-02-22 18:42:15 +0530442 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530443 qdf_mutex_t rt_debug_lock;
444 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800445 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800446 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530447 qdf_dma_addr_t tx_comp_doorbell_paddr;
448 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800449
450 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
451 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800452};
453
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800454/**
Houston Hoffman23e76f92016-02-26 12:19:11 -0800455 * FIXME: The following conversion routines are just stubs.
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800456 * They will be implemented fully by another update.
457 * The stubs will let the compile go ahead, and functionality
458 * is broken.
459 * This should be OK and IPA is not enabled yet
460 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700461static void *wlan_hdd_stub_priv_to_addr(uint32_t priv)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800462{
463 void *vaddr;
464 uint32_t ipa_priv = priv;
465
466 vaddr = &ipa_priv; /* just to use the var */
467 vaddr = NULL;
468 return vaddr;
469}
470
Jeff Johnsond7720632016-10-05 16:04:32 -0700471static uint32_t wlan_hdd_stub_addr_to_priv(void *ptr)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800472{
473 uint32_t ipa_priv = 0;
474
475 BUG_ON(ptr == NULL);
476 return ipa_priv;
477}
Leo Changcc923e22016-06-16 15:29:03 -0700478
479#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
480#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800481#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
482#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
483#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
484#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
485#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
486#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700487#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
488 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800489
490#define HDD_IPA_GET_IFACE_ID(_data) \
491 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
492
493#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530494 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800495 "%s:%d: "fmt, __func__, __LINE__, ## args)
496
Govind Singhb6a89772016-08-12 11:23:35 +0530497#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
498 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
499 "%s:%d: "fmt, __func__, __LINE__, ## args)
500
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
502 do { \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530503 QDF_TRACE(QDF_MODULE_ID_HDD, _lvl, "%s:", _prefix); \
504 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800505 } while (0)
506
507#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
508 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
509
510#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
511 do { \
512 hdd_ipa->ipa_rx_internel_drop_count++; \
513 } while (0)
514#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
515 do { \
516 hdd_ipa->ipa_rx_net_send_count++; \
517 } while (0)
518#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
519
Leo Chang07b28f62016-05-11 12:29:22 -0700520#if defined (QCA_WIFI_3_0) && defined (CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800521#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
522do { \
523 pipe_in.u.ul.rdy_ring_rp_va = \
524 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
525 pipe_in.u.ul.rdy_comp_ring_base_pa = \
526 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
527 pipe_in.u.ul.rdy_comp_ring_size = \
528 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
529 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
530 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
531 pipe_in.u.ul.rdy_comp_ring_wp_va = \
532 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800533} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700534
535#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800536#else
537/* Do nothing */
538#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
Leo Chang63d73612016-10-18 18:09:43 -0700539#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700540#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800541
Yun Parkb187d542016-11-14 18:10:04 -0800542#define HDD_IPA_DBG_DUMP_RX_LEN 32
543#define HDD_IPA_DBG_DUMP_TX_LEN 48
544
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545static struct hdd_ipa_adapter_2_client {
546 enum ipa_client_type cons_client;
547 enum ipa_client_type prod_client;
548} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
549 {
550 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
551 }, {
552 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
553 }, {
554 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
555 },
556};
557
558/* For Tx pipes, use Ethernet-II Header format */
559struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
560 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800561 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800562 0x00000000,
563 0x00000000
564 },
565 {
566 0x00000000
567 },
568 {
569 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
570 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
571 0x0008
572 }
573};
574
575/* For Tx pipes, use 802.3 Header format */
576static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
577 {
578 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
579 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
580 0x00 /* length can be zero */
581 },
582 {
583 /* LLC SNAP header 8 bytes */
584 0xaa, 0xaa,
585 {0x03, 0x00, 0x00, 0x00},
586 0x0008 /* type value(2 bytes) ,filled by wlan */
587 /* 0x0800 - IPV4, 0x86dd - IPV6 */
588 }
589};
590
591static const char *op_string[] = {
592 "TX_SUSPEND",
593 "TX_RESUME",
594 "RX_SUSPEND",
595 "RX_RESUME",
596 "STATS",
597};
598
599static struct hdd_ipa_priv *ghdd_ipa;
600
601/* Local Function Prototypes */
602static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
603 unsigned long data);
604static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
605 unsigned long data);
606
607static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Mohit Khannafa99aea2016-05-12 21:43:13 -0700608static void hdd_ipa_uc_proc_pending_event (struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800609
610/**
611 * hdd_ipa_is_enabled() - Is IPA enabled?
612 * @hdd_ctx: Global HDD context
613 *
614 * Return: true if IPA is enabled, false otherwise
615 */
616bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
617{
618 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
619}
620
621/**
622 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
623 * @hdd_ctx: Global HDD context
624 *
625 * Return: true if IPA uC offload is enabled, false otherwise
626 */
627bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
628{
629 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
630}
631
632/**
633 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
634 * @hdd_ctx: Global HDD context
635 *
636 * Return: true if STA mode IPA uC offload is enabled, false otherwise
637 */
638static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
639{
640 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
641}
642
643/**
Guolei Bianca144d82016-11-10 11:07:42 +0800644 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
645 * @hdd_ipa: Global HDD IPA context
646 *
647 * Return: None
648 */
649#ifdef IPA_UC_STA_OFFLOAD
650static inline void hdd_ipa_uc_sta_reset_sta_connected(
651 struct hdd_ipa_priv *hdd_ipa)
652{
653 vos_lock_acquire(&hdd_ipa->event_lock);
654 hdd_ipa->sta_connected = 0;
655 vos_lock_release(&hdd_ipa->event_lock);
656}
657#else
658static inline void hdd_ipa_uc_sta_reset_sta_connected(
659 struct hdd_ipa_priv *hdd_ipa)
660{
661}
662#endif
663
664/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800665 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
666 * @hdd_ipa: Global HDD IPA context
667 *
668 * Return: true if pre-filter is enabled, otherwise false
669 */
670static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
671{
672 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
673 HDD_IPA_PRE_FILTER_ENABLE_MASK);
674}
675
676/**
677 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
678 * @hdd_ipa: Global HDD IPA context
679 *
680 * Return: true if IPv6 is enabled, otherwise false
681 */
682static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
683{
684 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
685}
686
687/**
688 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
689 * @hdd_ipa: Global HDD IPA context
690 *
691 * Return: true if resource manager is enabled, otherwise false
692 */
693static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
694{
695 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
696}
697
698/**
699 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
700 * @hdd_ipa: Global HDD IPA context
701 *
702 * Return: true if resource manager is enabled, otherwise false
703 */
704static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
705{
706 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
707}
708
709/**
710 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
711 * @hdd_ipa: Global HDD IPA context
712 *
713 * Return: true if clock scaling is enabled, otherwise false
714 */
715static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
716{
717 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
718 HDD_IPA_CLK_SCALING_ENABLE_MASK |
719 HDD_IPA_RM_ENABLE_MASK);
720}
721
722/**
723 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
724 * @ctext: pointer to hdd context.
725 *
726 * If rt debug enabled, periodically called, and fill debug buffer
727 *
728 * Return: none
729 */
730static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
731{
732 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
733 struct hdd_ipa_priv *hdd_ipa;
734 struct uc_rt_debug_info *dump_info = NULL;
735
736 if (wlan_hdd_validate_context(hdd_ctx))
737 return;
738
739 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530740 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800741 "%s: IPA UC is not enabled", __func__);
742 return;
743 }
744
745 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
746
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530747 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800748 dump_info = &hdd_ipa->rt_bug_buffer[
749 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
750
Deepthi Gowri6acee342016-10-28 15:00:38 +0530751 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800752 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
753 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
754 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800755 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800756 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
757 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800758 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
759 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530760 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761
Anurag Chouhan210db072016-02-22 18:42:15 +0530762 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800763 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
764}
765
766/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700767 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800768 * @hdd_ctx: pointer to hdd context.
769 *
770 * If rt debug enabled, dump debug buffer contents based on requirement
771 *
772 * Return: none
773 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700774static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800775{
776 struct hdd_ipa_priv *hdd_ipa;
777 unsigned int dump_count;
778 unsigned int dump_index;
779 struct uc_rt_debug_info *dump_info = NULL;
780
781 if (wlan_hdd_validate_context(hdd_ctx))
782 return;
783
784 hdd_ipa = hdd_ctx->hdd_ipa;
785 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530786 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787 "%s: IPA UC is not enabled", __func__);
788 return;
789 }
790
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530791 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800792 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530793 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800794 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800795
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530796 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800797 for (dump_count = 0;
798 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
799 dump_count++) {
800 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
801 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
802 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530803 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530804 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800805 dump_info->time, dump_info->ipa_excep_count,
806 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800807 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800808 dump_info->rx_destructor_call,
809 dump_info->rx_discard_count);
810 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530811 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530812 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
814}
815
816/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700817 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
818 * __hdd_ipa_uc_rt_debug_host_dump
819 * @hdd_ctx: pointer to hdd context.
820 *
821 * If rt debug enabled, dump debug buffer contents based on requirement
822 *
823 * Return: none
824 */
825void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
826{
827 cds_ssr_protect(__func__);
828 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
829 cds_ssr_unprotect(__func__);
830}
831
832/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
834 * @ctext: pointer to hdd context.
835 *
836 * periodically called by timer expire
837 * will try to alloc dummy memory and detect out of memory condition
838 * if out of memory detected, dump wlan-ipa stats
839 *
840 * Return: none
841 */
842static void hdd_ipa_uc_rt_debug_handler(void *ctext)
843{
844 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700845 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800846 void *dummy_ptr = NULL;
847
848 if (wlan_hdd_validate_context(hdd_ctx))
849 return;
850
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700851 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
852
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800853 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -0800854 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800855 return;
856 }
857
858 /* Allocate dummy buffer periodically and free immediately. this will
859 * proactively detect OOM and if allocation fails dump ipa stats
860 */
861 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
862 GFP_KERNEL | GFP_ATOMIC);
863 if (!dummy_ptr) {
Yun Parkb187d542016-11-14 18:10:04 -0800864 hdd_alert("Dummy alloc fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800865 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
866 hdd_ipa_uc_stat_request(
Krunal Sonibe766b02016-03-10 13:00:44 -0800867 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800868 } else {
869 kfree(dummy_ptr);
870 }
871
Anurag Chouhan210db072016-02-22 18:42:15 +0530872 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873 HDD_IPA_UC_RT_DEBUG_PERIOD);
874}
875
876/**
Yun Parkb187d542016-11-14 18:10:04 -0800877 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 * @skb: packet pinter
879 *
880 * when free data packet, will be invoked by wlan client and will increase
881 * free counter
882 *
883 * Return: none
884 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700885static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800886{
887 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530888 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800889 "%s: invalid hdd context", __func__);
890 return;
891 }
892
893 ghdd_ipa->ipa_rx_destructor_count++;
894}
895
896/**
Yun Parkb187d542016-11-14 18:10:04 -0800897 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898 * @hdd_ctx: hdd main context
899 *
900 * free all rt debugging resources
901 *
902 * Return: none
903 */
904static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
905{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700906 struct hdd_ipa_priv *hdd_ipa;
907
908 if (wlan_hdd_validate_context(hdd_ctx))
909 return;
910
911 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800912
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530913 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800914
915 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -0800916 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917 return;
918 }
919
Anurag Chouhan210db072016-02-22 18:42:15 +0530920 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -0800921 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
922 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
923 }
924 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
925
926 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +0530927 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
928 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 }
Anurag Chouhan210db072016-02-22 18:42:15 +0530930 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931}
932
933/**
Yun Parkb187d542016-11-14 18:10:04 -0800934 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800935 * @hdd_ctx: hdd main context
936 *
937 * alloc and initialize all rt debugging resources
938 *
939 * Return: none
940 */
941static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
942{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700943 struct hdd_ipa_priv *hdd_ipa;
944
945 if (wlan_hdd_validate_context(hdd_ctx))
946 return;
947
948 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530950 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530952 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800953 sizeof(struct uc_rt_debug_info) *
954 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
955 hdd_ipa->ipa_tx_forward = 0;
956 hdd_ipa->ipa_rx_discard = 0;
957 hdd_ipa->ipa_rx_net_send_count = 0;
958 hdd_ipa->ipa_rx_internel_drop_count = 0;
959 hdd_ipa->ipa_rx_destructor_count = 0;
960
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800961 /* Reatime debug enable on feature enable */
962 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -0800963 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964 return;
965 }
Yun Parkdfc1da52016-11-15 14:50:11 -0800966
967 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
968 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
969 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
970 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
971
Anurag Chouhan210db072016-02-22 18:42:15 +0530972 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +0530974 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800975 HDD_IPA_UC_RT_DEBUG_PERIOD);
976
977}
978
979/**
Yun Parkb187d542016-11-14 18:10:04 -0800980 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
981 * @hdd_ipa: HDD IPA struct
982 *
983 * Dump entries in struct hdd_ipa
984 *
985 * Return: none
986 */
987static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
988{
989 int i;
990
991 /* HDD IPA */
992 hdd_err("==== HDD IPA ====\n"
993 "num_iface: %d\n"
994 "rm_state: %d\n"
995 "rm_lock: %p\n"
996 "uc_rm_work: %p\n"
997 "uc_op_work: %p\n"
998 "wake_lock: %p\n"
999 "wake_lock_work: %p\n"
1000 "wake_lock_released: %d\n"
1001 "prod_client: %d\n"
1002 "tx_ref_cnt: %d\n"
1003 "pm_queue_head----\n"
1004 "\thead: %p\n"
1005 "\ttail: %p\n"
1006 "\tqlen: %d\n"
1007 "pm_work: %p\n"
1008 "pm_lock: %p\n"
1009 "suspended: %d\n",
1010 hdd_ipa->num_iface,
1011 hdd_ipa->rm_state,
1012 &hdd_ipa->rm_lock,
1013 &hdd_ipa->uc_rm_work,
1014 &hdd_ipa->uc_op_work,
1015 &hdd_ipa->wake_lock,
1016 &hdd_ipa->wake_lock_work,
1017 hdd_ipa->wake_lock_released,
1018 hdd_ipa->prod_client,
1019 hdd_ipa->tx_ref_cnt.counter,
1020 hdd_ipa->pm_queue_head.head,
1021 hdd_ipa->pm_queue_head.tail,
1022 hdd_ipa->pm_queue_head.qlen,
1023 &hdd_ipa->pm_work,
1024 &hdd_ipa->pm_lock,
1025 hdd_ipa->suspended);
1026 hdd_err("\npending_hw_desc_cnt: %d\n"
1027 "hw_desc_cnt: %d\n"
1028 "q_lock: %p\n"
1029 "freeq_cnt: %d\n"
1030 "free_desc_head----\n"
1031 "\tnext: %p\n"
1032 "\tprev: %p\n"
1033 "pend_q_cnt: %d\n"
1034 "pend_desc_head----\n"
1035 "\tnext: %p\n"
1036 "\tprev: %p\n"
1037 "hdd_ctx: %p\n"
1038 "debugfs_dir: %p\n"
1039 "stats: %p\n"
1040 "ipv4_notifier: %p\n"
1041 "curr_prod_bw: %d\n"
1042 "curr_cons_bw: %d\n"
1043 "activated_fw_pipe: %d\n"
1044 "sap_num_connected_sta: %d\n"
1045 "sta_connected: %d\n",
1046 hdd_ipa->pending_hw_desc_cnt,
1047 hdd_ipa->hw_desc_cnt,
1048 &hdd_ipa->q_lock,
1049 hdd_ipa->freeq_cnt,
1050 hdd_ipa->free_desc_head.next,
1051 hdd_ipa->free_desc_head.prev,
1052 hdd_ipa->pend_q_cnt,
1053 hdd_ipa->pend_desc_head.next,
1054 hdd_ipa->pend_desc_head.prev,
1055 hdd_ipa->hdd_ctx,
1056 hdd_ipa->debugfs_dir,
1057 &hdd_ipa->stats,
1058 &hdd_ipa->ipv4_notifier,
1059 hdd_ipa->curr_prod_bw,
1060 hdd_ipa->curr_cons_bw,
1061 hdd_ipa->activated_fw_pipe,
1062 hdd_ipa->sap_num_connected_sta,
1063 (unsigned int)hdd_ipa->sta_connected
1064 );
1065 hdd_err("\ntx_pipe_handle: 0x%x\n"
1066 "rx_pipe_handle: 0x%x\n"
1067 "resource_loading: %d\n"
1068 "resource_unloading: %d\n"
1069 "pending_cons_req: %d\n"
1070 "pending_event----\n"
1071 "\tanchor.next: %p\n"
1072 "\tanchor.prev: %p\n"
1073 "\tcount: %d\n"
1074 "\tmax_size: %d\n"
1075 "event_lock: %p\n"
1076 "ipa_tx_packets_diff: %d\n"
1077 "ipa_rx_packets_diff: %d\n"
1078 "ipa_p_tx_packets: %d\n"
1079 "ipa_p_rx_packets: %d\n"
1080 "stat_req_reason: %d\n",
1081 hdd_ipa->tx_pipe_handle,
1082 hdd_ipa->rx_pipe_handle,
1083 hdd_ipa->resource_loading,
1084 hdd_ipa->resource_unloading,
1085 hdd_ipa->pending_cons_req,
1086 hdd_ipa->pending_event.anchor.next,
1087 hdd_ipa->pending_event.anchor.prev,
1088 hdd_ipa->pending_event.count,
1089 hdd_ipa->pending_event.max_size,
1090 &hdd_ipa->event_lock,
1091 hdd_ipa->ipa_tx_packets_diff,
1092 hdd_ipa->ipa_rx_packets_diff,
1093 hdd_ipa->ipa_p_tx_packets,
1094 hdd_ipa->ipa_p_rx_packets,
1095 hdd_ipa->stat_req_reason);
1096
1097 hdd_err("assoc_stas_map([id]is_reserved/sta_id): ");
1098 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
1099 hdd_err(" [%d]%d/%d", i,
1100 hdd_ipa->assoc_stas_map[i].is_reserved,
1101 hdd_ipa->assoc_stas_map[i].sta_id);
1102 }
1103}
1104
1105/**
1106 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1107 * @hdd_ipa: HDD IPA struct
1108 *
1109 * Dump entire struct hdd_ipa_sys_pipe
1110 *
1111 * Return: none
1112 */
1113static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1114{
1115 int i;
1116
1117 /* IPA SYS Pipes */
1118 hdd_err("==== IPA SYS Pipes ====\n");
1119
1120 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1121 struct hdd_ipa_sys_pipe *sys_pipe;
1122 struct ipa_sys_connect_params *ipa_sys_params;
1123
1124 sys_pipe = &hdd_ipa->sys_pipe[i];
1125 ipa_sys_params = &sys_pipe->ipa_sys_params;
1126
1127 hdd_err("sys_pipe[%d]----\n"
1128 "\tconn_hdl: 0x%x\n"
1129 "\tconn_hdl_valid: %d\n"
1130 "\tnat_en: %d\n"
1131 "\thdr_len %d\n"
1132 "\thdr_additional_const_len: %d\n"
1133 "\thdr_ofst_pkt_size_valid: %d\n"
1134 "\thdr_ofst_pkt_size: %d\n"
1135 "\thdr_little_endian: %d\n"
1136 "\tmode: %d\n"
1137 "\tclient: %d\n"
1138 "\tdesc_fifo_sz: %d\n"
1139 "\tpriv: %p\n"
1140 "\tnotify: %p\n"
1141 "\tskip_ep_cfg: %d\n"
1142 "\tkeep_ipa_awake: %d\n",
1143 i,
1144 sys_pipe->conn_hdl,
1145 sys_pipe->conn_hdl_valid,
1146 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1147 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1148 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1149 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1150 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1151 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1152 ipa_sys_params->ipa_ep_cfg.mode.mode,
1153 ipa_sys_params->client,
1154 ipa_sys_params->desc_fifo_sz,
1155 ipa_sys_params->priv,
1156 ipa_sys_params->notify,
1157 ipa_sys_params->skip_ep_cfg,
1158 ipa_sys_params->keep_ipa_awake);
1159 }
1160}
1161
1162/**
1163 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1164 * @hdd_ipa: HDD IPA struct
1165 *
1166 * Dump entire struct hdd_ipa_iface_context
1167 *
1168 * Return: none
1169 */
1170static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1171{
1172 int i;
1173
1174 /* IPA Interface Contexts */
1175 hdd_err("==== IPA Interface Contexts ====\n");
1176
1177 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1178 struct hdd_ipa_iface_context *iface_context;
1179
1180 iface_context = &hdd_ipa->iface_context[i];
1181
1182 hdd_err("iface_context[%d]----\n"
1183 "\thdd_ipa: %p\n"
1184 "\tadapter: %p\n"
1185 "\ttl_context: %p\n"
1186 "\tcons_client: %d\n"
1187 "\tprod_client: %d\n"
1188 "\tiface_id: %d\n"
1189 "\tsta_id: %d\n"
1190 "\tinterface_lock: %p\n"
1191 "\tifa_address: 0x%x\n",
1192 i,
1193 iface_context->hdd_ipa,
1194 iface_context->adapter,
1195 iface_context->tl_context,
1196 iface_context->cons_client,
1197 iface_context->prod_client,
1198 iface_context->iface_id,
1199 iface_context->sta_id,
1200 &iface_context->interface_lock,
1201 iface_context->ifa_address);
1202 }
1203}
1204
1205/**
1206 * hdd_ipa_dump_info() - dump HDD IPA struct
1207 * @pHddCtx: hdd main context
1208 *
1209 * Dump entire struct hdd_ipa
1210 *
1211 * Return: none
1212 */
1213void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1214{
1215 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1216
1217 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1218 hdd_ipa_dump_sys_pipe(hdd_ipa);
1219 hdd_ipa_dump_iface_context(hdd_ipa);
1220}
1221
1222/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001223 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001224 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001225 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1226 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001227 *
1228 * Return: true if IPA is enabled, false otherwise
1229 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001230static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001231 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1232{
1233 struct hdd_ipa_priv *hdd_ipa;
1234
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001235 *ipa_tx_diff = 0;
1236 *ipa_rx_diff = 0;
1237
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001238 if (wlan_hdd_validate_context(hdd_ctx))
1239 return;
1240
1241 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1242
1243 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1244 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001245 return;
1246 }
1247
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301248 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1250 (false == hdd_ipa->resource_loading)) {
1251 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1252 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001253 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254 *ipa_tx_diff, *ipa_rx_diff);
1255 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301256 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257 return;
1258}
1259
1260/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001261 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1262 * @hdd_ctx: Global HDD context
1263 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1264 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1265 *
1266 * Return: true if IPA is enabled, false otherwise
1267 */
1268void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1269 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1270{
1271 cds_ssr_protect(__func__);
1272 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1273 cds_ssr_unprotect(__func__);
1274}
1275
1276/**
1277 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001278 * @adapter: network adapter
1279 * @reason: STAT REQ Reason
1280 *
1281 * Return: None
1282 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001283static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001284{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001285 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001286 struct hdd_ipa_priv *hdd_ipa;
1287
1288 if (!adapter) {
1289 return;
1290 }
1291
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001292 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1293
1294 if (wlan_hdd_validate_context(hdd_ctx))
1295 return;
1296
1297 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1298 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1299 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001300 return;
1301 }
1302
Yun Parkb187d542016-11-14 18:10:04 -08001303 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301304 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1306 (false == hdd_ipa->resource_loading)) {
1307 hdd_ipa->stat_req_reason = reason;
1308 wma_cli_set_command(
1309 (int)adapter->sessionId,
1310 (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
1311 0, VDEV_CMD);
1312 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301313 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001314}
1315
1316/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001317 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1318 * @adapter: network adapter
1319 * @reason: STAT REQ Reason
1320 *
1321 * Return: None
1322 */
1323void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1324{
1325 cds_ssr_protect(__func__);
1326 __hdd_ipa_uc_stat_request(adapter, reason);
1327 cds_ssr_unprotect(__func__);
1328}
1329
1330/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001331 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1332 * @hdd_ipa: Global HDD IPA context
1333 * @sta_add: Should station be added
1334 * @sta_id: ID of the station being queried
1335 *
1336 * Return: true if the station was found
1337 */
1338static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1339 bool sta_add, uint8_t sta_id)
1340{
1341 bool sta_found = false;
1342 uint8_t idx;
1343 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1344 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1345 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1346 sta_found = true;
1347 break;
1348 }
1349 }
1350 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301351 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001352 "%s: STA ID %d already exist, cannot add",
1353 __func__, sta_id);
1354 return sta_found;
1355 }
1356 if (sta_add) {
1357 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1358 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1359 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1360 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1361 return sta_found;
1362 }
1363 }
1364 }
1365 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301366 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001367 "%s: STA ID %d does not exist, cannot delete",
1368 __func__, sta_id);
1369 return sta_found;
1370 }
1371 if (!sta_add) {
1372 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1373 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1374 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1375 hdd_ipa->assoc_stas_map[idx].is_reserved =
1376 false;
1377 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1378 return sta_found;
1379 }
1380 }
1381 }
1382 return sta_found;
1383}
1384
1385/**
1386 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1387 * @hdd_ipa: Global HDD IPA context
1388 *
1389 * Return: 0 on success, negative errno if error
1390 */
1391static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1392{
1393 int result;
1394 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001395 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001396
1397 /* ACTIVATE TX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301398 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001399 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1400 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1402 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301403 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001404 "%s: Enable TX PIPE fail, code %d",
1405 __func__, result);
1406 return result;
1407 }
1408 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1409 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301410 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411 "%s: Resume TX PIPE fail, code %d",
1412 __func__, result);
1413 return result;
1414 }
Leo Changfdb45c32016-10-28 11:09:23 -07001415 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001416
1417 /* ACTIVATE RX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301418 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001419 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1420 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001421 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1422 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301423 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001424 "%s: Enable RX PIPE fail, code %d",
1425 __func__, result);
1426 return result;
1427 }
1428 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1429 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301430 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001431 "%s: Resume RX PIPE fail, code %d",
1432 __func__, result);
1433 return result;
1434 }
Leo Changfdb45c32016-10-28 11:09:23 -07001435 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, true, false);
Leo Change3e49442015-10-26 20:07:13 -07001436 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001437 return 0;
1438}
1439
1440/**
1441 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1442 * @hdd_ipa: Global HDD IPA context
1443 *
1444 * Return: 0 on success, negative errno if error
1445 */
1446static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1447{
1448 int result;
1449
Leo Change3e49442015-10-26 20:07:13 -07001450 hdd_ipa->ipa_pipes_down = true;
1451
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301452 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
1454 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301455 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001456 "%s: Suspend RX PIPE fail, code %d",
1457 __func__, result);
1458 return result;
1459 }
1460 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1461 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301462 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001463 "%s: Disable RX PIPE fail, code %d",
1464 __func__, result);
1465 return result;
1466 }
1467
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301468 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001469 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
1470 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301471 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001472 "%s: Suspend TX PIPE fail, code %d",
1473 __func__, result);
1474 return result;
1475 }
1476 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1477 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301478 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001479 "%s: Disable TX PIPE fail, code %d",
1480 __func__, result);
1481 return result;
1482 }
1483
1484 return 0;
1485}
1486
1487/**
1488 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1489 * @hdd_ipa: Global HDD IPA context
1490 *
1491 * Return: 0 on success, negative errno if error
1492 */
1493static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1494{
1495 hdd_ipa->activated_fw_pipe = 0;
1496 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001497
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498 /* If RM feature enabled
1499 * Request PROD Resource first
1500 * PROD resource may return sync or async manners */
Yun Park4cab6ee2015-10-27 11:43:40 -07001501 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
1502 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1503 /* RM PROD request sync return
1504 * enable pipe immediately
1505 */
1506 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301507 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001508 "%s: IPA WDI Pipe activation failed",
1509 __func__);
1510 hdd_ipa->resource_loading = false;
1511 return -EBUSY;
1512 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513 }
1514 } else {
1515 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001516 * Just enabled all the PIPEs
1517 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001518 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301519 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001520 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001521 __func__);
1522 hdd_ipa->resource_loading = false;
1523 return -EBUSY;
1524 }
1525 hdd_ipa->resource_loading = false;
1526 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001527
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301528 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001529 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001530 return 0;
1531}
1532
1533/**
1534 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1535 * @hdd_ipa: Global HDD IPA context
1536 *
1537 * Return: None
1538 */
1539static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1540{
1541 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001542 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001543
Yun Park7c4f31b2016-11-30 10:09:21 -08001544 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
1545 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
1546 QDF_ASSERT(0);
1547 return;
1548 }
1549
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001550 hdd_ipa->resource_unloading = true;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301551 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW RX PIPE", __func__);
Leo Changfdb45c32016-10-28 11:09:23 -07001552 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, false, false);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301553 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW TX PIPE", __func__);
Leo Changfdb45c32016-10-28 11:09:23 -07001554 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555}
1556
1557/**
1558 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
1559 * @context: User context registered with TL (the IPA Global context is
1560 * registered
1561 * @rxpkt: Packet containing the notification
1562 * @staid: ID of the station associated with the packet
1563 *
1564 * Return: None
1565 */
1566static void
1567hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
1568{
1569 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301570 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001571
1572 /*
1573 * When SSR is going on or driver is unloading, just return.
1574 */
1575 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301576 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001577 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001578
1579 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1580 return;
1581
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301582 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001583 __func__, event);
1584
1585 switch (event) {
1586 case IPA_RM_RESOURCE_GRANTED:
1587 /* Differed RM Granted */
1588 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301589 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001590 if ((false == hdd_ipa->resource_unloading) &&
1591 (!hdd_ipa->activated_fw_pipe)) {
1592 hdd_ipa_uc_enable_pipes(hdd_ipa);
1593 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301594 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001595 break;
1596
1597 case IPA_RM_RESOURCE_RELEASED:
1598 /* Differed RM Released */
1599 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001600 break;
1601
1602 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301603 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001604 "%s, invalid event code %d", __func__, event);
1605 break;
1606 }
1607}
1608
1609/**
1610 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
1611 * @hdd_ipa: Global HDD IPA context
1612 * @event: IPA resource manager event to be deferred
1613 *
1614 * This function is called when a resource manager event is received
1615 * from firmware in interrupt context. This function will defer the
1616 * handling to the OL RX thread
1617 *
1618 * Return: None
1619 */
1620static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
1621{
1622 enum ipa_rm_event event;
1623 struct uc_rm_work_struct *uc_rm_work = container_of(work,
1624 struct uc_rm_work_struct, work);
1625 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
1626 struct hdd_ipa_priv, uc_rm_work);
1627
1628 cds_ssr_protect(__func__);
1629 event = uc_rm_work->event;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301630 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001631 "%s, posted event %d", __func__, event);
1632
1633 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
1634 cds_ssr_unprotect(__func__);
1635
1636 return;
1637}
1638
1639/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001640 * hdd_ipa_uc_op_cb() - IPA uC operation callback
1641 * @op_msg: operation message received from firmware
1642 * @usr_ctxt: user context registered with TL (we register the HDD Global
1643 * context)
1644 *
1645 * Return: None
1646 */
1647static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
1648{
1649 struct op_msg_type *msg = op_msg;
1650 struct ipa_uc_fw_stats *uc_fw_stat;
1651 struct IpaHwStatsWDIInfoData_t ipa_stat;
1652 struct hdd_ipa_priv *hdd_ipa;
1653 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301654 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001655
1656 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301657 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658 return;
1659 }
1660
1661 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301662 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001663 "%s, INVALID OPCODE %d", __func__, msg->op_code);
1664 return;
1665 }
1666
1667 hdd_ctx = (hdd_context_t *) usr_ctxt;
1668
1669 /*
1670 * When SSR is going on or driver is unloading, just return.
1671 */
1672 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301673 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301674 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001675 return;
1676 }
1677
1678 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1679
Govind Singhb6a89772016-08-12 11:23:35 +05301680 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001681 "%s, OPCODE %s", __func__, op_string[msg->op_code]);
1682
1683 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
1684 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301685 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686 hdd_ipa->activated_fw_pipe++;
1687 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
1688 hdd_ipa->resource_loading = false;
1689 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08001690 if (hdd_ipa->pending_cons_req)
1691 ipa_rm_notify_completion(
1692 IPA_RM_RESOURCE_GRANTED,
1693 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08001694 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301696 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001697 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301699 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700 hdd_ipa->activated_fw_pipe--;
1701 if (!hdd_ipa->activated_fw_pipe) {
1702 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08001703 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1704 ipa_rm_release_resource(
1705 IPA_RM_RESOURCE_WLAN_PROD);
1706 /* Sync return success from IPA
1707 * Enable/resume all the PIPEs */
1708 hdd_ipa->resource_unloading = false;
1709 hdd_ipa_uc_proc_pending_event(hdd_ipa);
1710 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301712 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001713 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001714 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001715 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301717 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001719 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720 "CE RING SIZE: %d\n"
1721 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001722 (unsigned long long)res->ce_sr_base_paddr,
1723 res->ce_sr_ring_size,
1724 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301725 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001726 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001727 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001728 "COMP RING SIZE: %d\n"
1729 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001730 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001731 (unsigned long long)res->tx_comp_ring_base_paddr,
1732 res->tx_comp_ring_size,
1733 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001734 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301735 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001737 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001739 "IND RING DBELL : 0x%llx\n"
1740 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001741 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08001742 "NUM TX FWD OK : %llu\n"
1743 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08001744 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001745 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08001746 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
1747 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08001749 hdd_ipa->stats.num_tx_fwd_ok,
1750 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301751 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752 "==== IPA_UC WLAN_HOST CONTROL ====\n"
1753 "SAP NUM STAs: %d\n"
1754 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001755 "CONCURRENT MODE: %s\n"
1756 "TX PIPE HDL: 0x%x\n"
1757 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758 "RSC LOADING : %d\n"
1759 "RSC UNLOADING : %d\n"
1760 "PNDNG CNS RQT : %d",
1761 hdd_ipa->sap_num_connected_sta,
1762 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08001763 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001764 hdd_ipa->tx_pipe_handle,
1765 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08001766 hdd_ipa->resource_loading,
1767 hdd_ipa->resource_unloading,
1768 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769
1770 /* STATs from FW */
1771 uc_fw_stat = (struct ipa_uc_fw_stats *)
1772 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301773 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774 "==== IPA_UC WLAN_FW TX ====\n"
1775 "COMP RING BASE: 0x%x\n"
1776 "COMP RING SIZE: %d\n"
1777 "COMP RING DBELL : 0x%x\n"
1778 "COMP RING DBELL IND VAL : %d\n"
1779 "COMP RING DBELL CACHED VAL : %d\n"
1780 "COMP RING DBELL CACHED VAL : %d\n"
1781 "PKTS ENQ : %d\n"
1782 "PKTS COMP : %d\n"
1783 "IS SUSPEND : %d\n"
1784 "RSVD : 0x%x",
1785 uc_fw_stat->tx_comp_ring_base,
1786 uc_fw_stat->tx_comp_ring_size,
1787 uc_fw_stat->tx_comp_ring_dbell_addr,
1788 uc_fw_stat->tx_comp_ring_dbell_ind_val,
1789 uc_fw_stat->tx_comp_ring_dbell_cached_val,
1790 uc_fw_stat->tx_comp_ring_dbell_cached_val,
1791 uc_fw_stat->tx_pkts_enqueued,
1792 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08001793 uc_fw_stat->tx_is_suspend,
1794 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301795 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001796 "==== IPA_UC WLAN_FW RX ====\n"
1797 "IND RING BASE: 0x%x\n"
1798 "IND RING SIZE: %d\n"
1799 "IND RING DBELL : 0x%x\n"
1800 "IND RING DBELL IND VAL : %d\n"
1801 "IND RING DBELL CACHED VAL : %d\n"
1802 "RDY IND ADDR : 0x%x\n"
1803 "RDY IND CACHE VAL : %d\n"
1804 "RFIL IND : %d\n"
1805 "NUM PKT INDICAT : %d\n"
1806 "BUF REFIL : %d\n"
1807 "NUM DROP NO SPC : %d\n"
1808 "NUM DROP NO BUF : %d\n"
1809 "IS SUSPND : %d\n"
1810 "RSVD : 0x%x\n",
1811 uc_fw_stat->rx_ind_ring_base,
1812 uc_fw_stat->rx_ind_ring_size,
1813 uc_fw_stat->rx_ind_ring_dbell_addr,
1814 uc_fw_stat->rx_ind_ring_dbell_ind_val,
1815 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
1816 uc_fw_stat->rx_ind_ring_rdidx_addr,
1817 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
1818 uc_fw_stat->rx_refill_idx,
1819 uc_fw_stat->rx_num_pkts_indicated,
1820 uc_fw_stat->rx_buf_refilled,
1821 uc_fw_stat->rx_num_ind_drop_no_space,
1822 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08001823 uc_fw_stat->rx_is_suspend,
1824 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825 /* STATs from IPA */
1826 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301827 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001828 "==== IPA_UC IPA TX ====\n"
1829 "NUM PROCD : %d\n"
1830 "CE DBELL : 0x%x\n"
1831 "NUM DBELL FIRED : %d\n"
1832 "COMP RNG FULL : %d\n"
1833 "COMP RNG EMPT : %d\n"
1834 "COMP RNG USE HGH : %d\n"
1835 "COMP RNG USE LOW : %d\n"
1836 "BAM FIFO FULL : %d\n"
1837 "BAM FIFO EMPT : %d\n"
1838 "BAM FIFO USE HGH : %d\n"
1839 "BAM FIFO USE LOW : %d\n"
1840 "NUM DBELL : %d\n"
1841 "NUM UNEXP DBELL : %d\n"
1842 "NUM BAM INT HDL : 0x%x\n"
1843 "NUM BAM INT NON-RUN : 0x%x\n"
1844 "NUM QMB INT HDL : 0x%x",
1845 ipa_stat.tx_ch_stats.num_pkts_processed,
1846 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
1847 ipa_stat.tx_ch_stats.num_db_fired,
1848 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
1849 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
1850 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
1851 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
1852 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
1853 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
1854 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
1855 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
1856 ipa_stat.tx_ch_stats.num_db,
1857 ipa_stat.tx_ch_stats.num_unexpected_db,
1858 ipa_stat.tx_ch_stats.num_bam_int_handled,
1859 ipa_stat.tx_ch_stats.
1860 num_bam_int_in_non_runnning_state,
1861 ipa_stat.tx_ch_stats.num_qmb_int_handled);
1862
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301863 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001864 "==== IPA_UC IPA RX ====\n"
1865 "MAX OST PKT : %d\n"
1866 "NUM PKT PRCSD : %d\n"
1867 "RNG RP : 0x%x\n"
1868 "COMP RNG FULL : %d\n"
1869 "COMP RNG EMPT : %d\n"
1870 "COMP RNG USE HGH : %d\n"
1871 "COMP RNG USE LOW : %d\n"
1872 "BAM FIFO FULL : %d\n"
1873 "BAM FIFO EMPT : %d\n"
1874 "BAM FIFO USE HGH : %d\n"
1875 "BAM FIFO USE LOW : %d\n"
1876 "NUM DB : %d\n"
1877 "NUM UNEXP DB : %d\n"
1878 "NUM BAM INT HNDL : 0x%x\n",
1879 ipa_stat.rx_ch_stats.max_outstanding_pkts,
1880 ipa_stat.rx_ch_stats.num_pkts_processed,
1881 ipa_stat.rx_ch_stats.rx_ring_rp_value,
1882 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
1883 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
1884 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
1885 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
1886 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
1887 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
1888 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
1889 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
1890 ipa_stat.rx_ch_stats.num_db,
1891 ipa_stat.rx_ch_stats.num_unexpected_db,
1892 ipa_stat.rx_ch_stats.num_bam_int_handled);
1893 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
1894 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
1895 /* STATs from FW */
1896 uc_fw_stat = (struct ipa_uc_fw_stats *)
1897 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301898 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001899 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
1900 uc_fw_stat->tx_pkts_completed,
1901 hdd_ipa->ipa_p_tx_packets);
1902 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
1903 (uc_fw_stat->rx_num_ind_drop_no_space +
1904 uc_fw_stat->rx_num_ind_drop_no_buf +
1905 uc_fw_stat->rx_num_pkts_indicated),
1906 hdd_ipa->ipa_p_rx_packets);
1907
1908 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
1909 hdd_ipa->ipa_p_rx_packets =
1910 (uc_fw_stat->rx_num_ind_drop_no_space +
1911 uc_fw_stat->rx_num_ind_drop_no_buf +
1912 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301913 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001914 } else {
Yun Park8292dcb2016-10-07 16:46:06 -07001915 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
1916 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001917 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301918 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001919}
1920
1921
1922/**
1923 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
1924 * @adapter: device adapter instance
1925 * @offload_type: MCC or SCC
1926 * @enable: TX offload enable or disable
1927 *
1928 * Return: none
1929 */
1930static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001931 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001932{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001933 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001934 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07001935 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001936 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001938 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001939 return;
1940
Yun Park8292dcb2016-10-07 16:46:06 -07001941 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001942 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07001943
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001944 if (!iface_context) {
1945 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1946 "Interface context is NULL");
1947 return;
1948 }
1949
1950 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07001951 /* IPA offload status is already set as desired */
1952 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001953 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
1954 "IPA offload status is already set",
1955 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07001956 return;
1957 }
1958
Yun Park4540e862016-11-10 16:30:06 -08001959 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1960 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1961 "invalid session id: %d, offload_type=%d, enable=%d",
1962 adapter->sessionId, offload_type, enable);
1963 return;
1964 }
1965
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301966 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967 sizeof(ipa_offload_enable_disable));
1968 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001969 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 ipa_offload_enable_disable.enable = enable;
1971
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301972 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07001973 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 ipa_offload_enable_disable.offload_type,
1975 ipa_offload_enable_disable.vdev_id,
1976 ipa_offload_enable_disable.enable);
1977
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301978 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001979 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
1980 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301981 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08001982 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
1983 __func__,
1984 ipa_offload_enable_disable.offload_type,
1985 ipa_offload_enable_disable.vdev_id,
1986 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07001987 } else {
1988 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001989 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07001990 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 }
1992}
1993
1994/**
1995 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
1996 * @work: uC OP work
1997 *
1998 * Return: None
1999 */
2000static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2001{
2002 struct op_msg_type *msg;
2003 struct uc_op_work_struct *uc_op_work = container_of(work,
2004 struct uc_op_work_struct, work);
2005 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2006
2007 cds_ssr_protect(__func__);
2008
2009 msg = uc_op_work->msg;
2010 uc_op_work->msg = NULL;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302011 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012 "%s, posted msg %d", __func__, msg->op_code);
2013
2014 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2015
2016 cds_ssr_unprotect(__func__);
2017
2018 return;
2019}
2020
2021/**
2022 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2023 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2024 * @op_msg: operation message received from firmware
2025 * @hdd_ctx: Global HDD context
2026 *
2027 * Return: None
2028 */
2029static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2030{
2031 struct hdd_ipa_priv *hdd_ipa;
2032 struct op_msg_type *msg;
2033 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302034 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002035
2036 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302037 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002039
2040 msg = (struct op_msg_type *)op_msg;
2041 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2042
2043 if (unlikely(!hdd_ipa))
2044 goto end;
2045
2046 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302047 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048 __func__, msg->op_code);
2049 goto end;
2050 }
2051
2052 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2053 if (uc_op_work->msg)
2054 /* When the same uC OPCODE is already pended, just return */
2055 goto end;
2056
2057 uc_op_work->msg = msg;
2058 schedule_work(&uc_op_work->work);
2059 return;
2060
2061end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302062 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002063}
2064
2065/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002066 * hdd_ipa_init_uc_op_work - init ipa uc op work
2067 * @work: struct work_struct
2068 * @work_handler: work_handler
2069 *
2070 * Return: none
2071 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002072static void hdd_ipa_init_uc_op_work(struct work_struct *work,
2073 work_func_t work_handler)
2074{
2075 INIT_WORK(work, work_handler);
2076}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002077
2078
2079/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002080 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2081 * @hdd_ctx: Global HDD context
2082 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302083 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302085static QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002086{
2087 struct ipa_wdi_in_params pipe_in;
2088 struct ipa_wdi_out_params pipe_out;
2089 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2090 p_cds_contextType cds_ctx = hdd_ctx->pcds_context;
2091 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07002092 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002093
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302094 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2095 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002096
Anurag Chouhanffb21542016-02-17 14:33:03 +05302097 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302098 qdf_mutex_create(&ipa_ctxt->event_lock);
2099 qdf_mutex_create(&ipa_ctxt->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100
2101 /* TX PIPE */
2102 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2103 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2104 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2105 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2106 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2107 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2108 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2109 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2110 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2111 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2112 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2113 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2114 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302115 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002116 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
2117 pipe_in.sys.keep_ipa_awake = true;
2118 }
2119
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002120 pipe_in.u.dl.comp_ring_base_pa =
2121 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002122 pipe_in.u.dl.comp_ring_size =
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002123 ipa_ctxt->ipa_resource.tx_comp_ring_size *
2124 sizeof(qdf_dma_addr_t);
2125 pipe_in.u.dl.ce_ring_base_pa =
2126 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
2127 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
2128 pipe_in.u.dl.ce_ring_size =
2129 ipa_ctxt->ipa_resource.ce_sr_ring_size;
2130 pipe_in.u.dl.num_tx_buffers =
2131 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002132
2133 /* Connect WDI IPA PIPE */
2134 ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
2135 /* Micro Controller Doorbell register */
Govind Singh0487bf22016-08-24 23:08:57 +05302136 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2137 "%s CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
2138 __func__, (unsigned int)pipe_out.uc_door_bell_pa,
2139 ipa_ctxt->tx_pipe_handle);
Leo Chang3bc8fed2015-11-13 10:59:47 -08002140 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002141 /* WLAN TX PIPE Handle */
2142 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302143 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002144 "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x,"
2145 " CERZ %d, NB %d, CDBPAD 0x%x",
2146 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
2147 pipe_in.u.dl.comp_ring_size,
2148 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
2149 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
2150 pipe_in.u.dl.ce_ring_size,
2151 pipe_in.u.dl.num_tx_buffers,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002152 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002153
2154 /* RX PIPE */
2155 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2156 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
2157 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
2158 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
2159 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2160 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
2161 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
2162 sizeof(struct sps_iovec);
2163 pipe_in.sys.notify = hdd_ipa_w2i_cb;
2164 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302165 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
2167 pipe_in.sys.keep_ipa_awake = true;
2168 }
2169
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002170 pipe_in.u.ul.rdy_ring_base_pa =
2171 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
2172 pipe_in.u.ul.rdy_ring_size =
2173 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
2174 pipe_in.u.ul.rdy_ring_rp_pa =
2175 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002176 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002177 ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
Leo Chang3bc8fed2015-11-13 10:59:47 -08002178 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002179 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302180 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002181 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
2182 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
2183 pipe_in.u.ul.rdy_ring_size,
2184 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002185 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002186
Leo Changfdb45c32016-10-28 11:09:23 -07002187 cdp_ipa_set_doorbell_paddr(soc, cds_ctx->pdev_txrx_ctx,
2188 ipa_ctxt->tx_comp_doorbell_paddr,
2189 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002190
Leo Changfdb45c32016-10-28 11:09:23 -07002191 cdp_ipa_register_op_cb(soc, cds_ctx->pdev_txrx_ctx,
2192 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002193
2194 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08002195 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002196 hdd_ipa_uc_fw_op_event_handler);
2197 ipa_ctxt->uc_op_work[i].msg = NULL;
2198 }
2199
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302200 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002201}
2202
Leo Change3e49442015-10-26 20:07:13 -07002203/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002204 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002205 * @hdd_ctx: hdd main context
2206 *
2207 * Force shutdown IPA pipe
2208 * Independent of FW pipe status, IPA pipe shutdonw progress
2209 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2210 * independent from FW pipe status
2211 *
2212 * Return: NONE
2213 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002214static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002215{
2216 struct hdd_ipa_priv *hdd_ipa;
2217
2218 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2219 return;
2220
2221 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2222 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302223 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07002224 "IPA pipes are not down yet, force shutdown");
2225 hdd_ipa_uc_disable_pipes(hdd_ipa);
2226 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302227 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Leo Change3e49442015-10-26 20:07:13 -07002228 "IPA pipes are down, do nothing");
2229 }
2230
2231 return;
2232}
2233
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002234/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002235 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2236 * __hdd_ipa_uc_force_pipe_shutdown
2237 * @hdd_ctx: hdd main context
2238 *
2239 * Force shutdown IPA pipe
2240 * Independent of FW pipe status, IPA pipe shutdonw progress
2241 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2242 * independent from FW pipe status
2243 *
2244 * Return: NONE
2245 */
2246void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2247{
2248 cds_ssr_protect(__func__);
2249 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2250 cds_ssr_unprotect(__func__);
2251}
2252
2253/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302254 * hdd_ipa_msg_free_fn() - Free an IPA message
2255 * @buff: pointer to the IPA message
2256 * @len: length of the IPA message
2257 * @type: type of IPA message
2258 *
2259 * Return: None
2260 */
2261static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2262{
2263 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "msg type:%d, len:%d", type, len);
2264 ghdd_ipa->stats.num_free_msg++;
2265 qdf_mem_free(buff);
2266}
2267
Govind Singh9c58eba2016-09-02 16:23:06 +05302268/**
jge62037862016-12-09 10:44:33 +08002269 * hdd_ipa_uc_send_evt() - send event to ipa
2270 * @hdd_ctx: pointer to hdd context
2271 * @type: event type
2272 * @mac_addr: pointer to mac address
2273 *
2274 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05302275 *
2276 * Return: 0 - Success
2277 */
jge62037862016-12-09 10:44:33 +08002278static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
2279 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05302280{
jge62037862016-12-09 10:44:33 +08002281 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05302282 struct ipa_msg_meta meta;
2283 struct ipa_wlan_msg *msg;
2284 int ret = 0;
jge62037862016-12-09 10:44:33 +08002285
2286 meta.msg_len = sizeof(struct ipa_wlan_msg);
2287 msg = qdf_mem_malloc(meta.msg_len);
2288 if (msg == NULL) {
2289 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2290 "msg allocation failed");
2291 return -ENOMEM;
2292 }
2293
2294 meta.msg_type = type;
2295 strlcpy(msg->name, adapter->dev->name,
2296 IPA_RESOURCE_NAME_MAX);
2297 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
2298 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
2299 msg->name, meta.msg_type);
2300 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2301 if (ret) {
2302 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2303 "%s: Evt: %d fail:%d",
2304 msg->name, meta.msg_type, ret);
2305 qdf_mem_free(msg);
2306 return ret;
2307 }
2308
2309 hdd_ipa->stats.num_send_msg++;
2310
2311 return ret;
2312}
2313
2314/**
2315 * hdd_ipa_uc_disconnect_client() - send client disconnect event
2316 * @hdd_ctx: pointer to hdd adapter
2317 *
2318 * Send disconnect client event to IPA driver during SSR
2319 *
2320 * Return: 0 - Success
2321 */
2322static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
2323{
2324 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2325 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05302326 int i;
2327
2328 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2329 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2330 continue;
2331 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08002332 (!adapter->aStaInfo[i].isDeauthInProgress) &&
2333 hdd_ipa->sap_num_connected_sta) {
2334 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
2335 adapter->aStaInfo[i].macAddrSTA.bytes);
2336 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05302337 }
2338 }
2339
2340 return ret;
2341}
2342
2343/**
jge62037862016-12-09 10:44:33 +08002344 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
2345 * @hdd_ctx: pointer to hdd adapter
2346 *
2347 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05302348 *
2349 * Return: 0 - Success
2350 */
jge62037862016-12-09 10:44:33 +08002351
2352static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
2353{
2354 int ret = 0;
2355
2356 if (adapter->ipa_context)
2357 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
2358 adapter->dev->dev_addr);
2359
2360 return ret;
2361}
2362
2363#ifdef IPA_UC_STA_OFFLOAD
2364/**
2365 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
2366 * @hdd_ctx: pointer to hdd adapter
2367 *
2368 * Send disconnect sta event to IPA driver during SSR
2369 *
2370 * Return: 0 - Success
2371 */
2372static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2373{
2374 hdd_station_ctx_t *pHddStaCtx;
2375 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2376 int ret = 0;
2377
2378 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa) &&
2379 hdd_ipa->sta_connected) {
2380 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2381 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
2382 pHddStaCtx->conn_info.bssId);
2383 }
2384
2385 return ret;
2386}
2387#else
2388static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2389{
2390 return 0;
2391}
2392
2393#endif
2394
2395/**
2396 * hdd_ipa_uc_disconnect() - send disconnect ipa event
2397 * @hdd_ctx: pointer to hdd context
2398 *
2399 * Send disconnect event to IPA driver during SSR
2400 *
2401 * Return: 0 - Success
2402 */
2403static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05302404{
2405 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2406 QDF_STATUS status;
2407 hdd_adapter_t *adapter;
2408 int ret = 0;
2409
Govind Singh9c58eba2016-09-02 16:23:06 +05302410 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2411 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2412 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08002413 if (adapter->device_mode == QDF_SAP_MODE) {
2414 hdd_ipa_uc_disconnect_client(adapter);
2415 hdd_ipa_uc_disconnect_ap(adapter);
2416 } else if (adapter->device_mode == QDF_STA_MODE) {
2417 hdd_ipa_uc_disconnect_sta(adapter);
2418 }
2419
Govind Singh9c58eba2016-09-02 16:23:06 +05302420 status = hdd_get_next_adapter(
2421 hdd_ctx, adapter_node, &next);
2422 adapter_node = next;
2423 }
2424
2425 return ret;
2426}
2427
2428/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002429 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002430 *
2431 * Deinit basic IPA UC host side to be in sync reloaded FW during
2432 * SSR
2433 *
2434 * Return: 0 - Success
2435 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002436static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002437{
2438 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2439 int idx;
2440 struct hdd_ipa_iface_context *iface_context;
2441
Leo Chang3bc8fed2015-11-13 10:59:47 -08002442 if ((!hdd_ipa) || (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002443 return 0;
2444
jge62037862016-12-09 10:44:33 +08002445 /* send disconnect to ipa driver */
2446 hdd_ipa_uc_disconnect(hdd_ipa->hdd_ctx);
2447
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002448 /* Clean up HDD IPA interfaces */
2449 for (idx = 0; (hdd_ipa->num_iface > 0) &&
2450 (idx < HDD_IPA_MAX_IFACE); idx++) {
2451 iface_context = &hdd_ipa->iface_context[idx];
2452 if (iface_context && iface_context->adapter)
2453 hdd_ipa_cleanup_iface(iface_context);
2454 }
2455
2456 /* After SSR, wlan driver reloads FW again. But we need to protect
2457 * IPA submodule during SSR transient state. So deinit basic IPA
2458 * UC host side to be in sync with reloaded FW during SSR
2459 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08002460 if (!hdd_ipa->ipa_pipes_down)
2461 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002462
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302463 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002464 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2465 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
2466 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
2467 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302468 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002469
Guolei Bianca144d82016-11-10 11:07:42 +08002470 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
2471 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
2472
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002473 /* Full IPA driver cleanup not required since wlan driver is now
2474 * unloaded and reloaded after SSR.
2475 */
2476 return 0;
2477}
2478
2479/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002480 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
2481 *
2482 * Deinit basic IPA UC host side to be in sync reloaded FW during
2483 * SSR
2484 *
2485 * Return: 0 - Success
2486 */
2487int hdd_ipa_uc_ssr_deinit(void)
2488{
2489 int ret;
2490
2491 cds_ssr_protect(__func__);
2492 ret = __hdd_ipa_uc_ssr_deinit();
2493 cds_ssr_unprotect(__func__);
2494
2495 return ret;
2496}
2497
2498/**
2499 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002500 *
2501 * Init basic IPA UC host side to be in sync with reloaded FW after
2502 * SSR to resume IPA UC operations
2503 *
2504 * Return: 0 - Success
2505 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002506static int __hdd_ipa_uc_ssr_reinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002507{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002508
2509 /* After SSR is complete, IPA UC can resume operation. But now wlan
2510 * driver will be unloaded and reloaded, which takes care of IPA cleanup
2511 * and initialization. This is a placeholder func if IPA has to resume
2512 * operations without driver reload.
2513 */
2514 return 0;
2515}
Leo Chang3bc8fed2015-11-13 10:59:47 -08002516
2517/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002518 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
2519 *
2520 * Init basic IPA UC host side to be in sync with reloaded FW after
2521 * SSR to resume IPA UC operations
2522 *
2523 * Return: 0 - Success
2524 */
2525int hdd_ipa_uc_ssr_reinit(void)
2526{
2527 int ret;
2528
2529 cds_ssr_protect(__func__);
2530 ret = __hdd_ipa_uc_ssr_reinit();
2531 cds_ssr_unprotect(__func__);
2532
2533 return ret;
2534}
2535
2536/**
2537 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08002538 * @hdd_ctx: Global HDD context
2539 * @skb: skb sent to IPA
2540 * @session_id: send packet instance session id
2541 *
2542 * Send TX packet which generated by system to IPA.
2543 * This routine only will be used for function verification
2544 *
2545 * Return: NULL packet sent to IPA properly
2546 * NULL invalid packet drop
2547 * skb packet not sent to IPA. legacy data path should handle
2548 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002549static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002550 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07002551{
Leo Chang3bc8fed2015-11-13 10:59:47 -08002552 struct ipa_header *ipa_header;
2553 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002554 struct hdd_ipa_priv *hdd_ipa;
2555
2556 if (wlan_hdd_validate_context(hdd_ctx))
2557 return skb;
2558
2559 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002560
2561 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2562 return skb;
2563
Leo Chang07b28f62016-05-11 12:29:22 -07002564 if (!hdd_ipa)
2565 return skb;
2566
2567 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
2568 return skb;
2569
Leo Changcc923e22016-06-16 15:29:03 -07002570 if (skb_headroom(skb) <
2571 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07002572 return skb;
2573
Leo Chang3bc8fed2015-11-13 10:59:47 -08002574 ipa_header = (struct ipa_header *) skb_push(skb,
2575 sizeof(struct ipa_header));
2576 if (!ipa_header) {
2577 /* No headroom, legacy */
2578 return skb;
2579 }
2580 memset(ipa_header, 0, sizeof(*ipa_header));
2581 ipa_header->vdev_id = 0;
2582
2583 frag_header = (struct frag_header *) skb_push(skb,
2584 sizeof(struct frag_header));
2585 if (!frag_header) {
2586 /* No headroom, drop */
2587 kfree_skb(skb);
2588 return NULL;
2589 }
2590 memset(frag_header, 0, sizeof(*frag_header));
2591 frag_header->length = skb->len - sizeof(struct frag_header)
2592 - sizeof(struct ipa_header);
2593
2594 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
2595 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07002596}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002597
2598/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002599 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
2600 * @hdd_ctx: Global HDD context
2601 * @skb: skb sent to IPA
2602 * @session_id: send packet instance session id
2603 *
2604 * Send TX packet which generated by system to IPA.
2605 * This routine only will be used for function verification
2606 *
2607 * Return: NULL packet sent to IPA properly
2608 * NULL invalid packet drop
2609 * skb packet not sent to IPA. legacy data path should handle
2610 */
2611struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
2612 struct sk_buff *skb, uint8_t session_id)
2613{
2614 struct sk_buff *ret;
2615
2616 cds_ssr_protect(__func__);
2617 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
2618 cds_ssr_unprotect(__func__);
2619
2620 return ret;
2621}
2622
2623/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002624 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
2625 * @work: scheduled work
2626 *
2627 * When IPA resources are released in hdd_ipa_rm_try_release() we do
2628 * not want to immediately release the wake lock since the system
2629 * would then potentially try to suspend when there is a healthy data
2630 * rate. Deferred work is scheduled and this function handles the
2631 * work. When this function is called, if the IPA resource is still
2632 * released then we release the wake lock.
2633 *
2634 * Return: None
2635 */
2636static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
2637{
2638 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
2639 struct hdd_ipa_priv,
2640 wake_lock_work);
2641
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302642 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002643
2644 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
2645 goto end;
2646
2647 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302648 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002649 WIFI_POWER_EVENT_WAKELOCK_IPA);
2650
2651end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302652 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002653}
2654
2655/**
2656 * hdd_ipa_rm_request() - Request resource from IPA
2657 * @hdd_ipa: Global HDD IPA context
2658 *
2659 * Return: 0 on success, negative errno on error
2660 */
2661static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
2662{
2663 int ret = 0;
2664
2665 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2666 return 0;
2667
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302668 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002669
2670 switch (hdd_ipa->rm_state) {
2671 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302672 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002673 return 0;
2674 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302675 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002676 return -EINPROGRESS;
2677 case HDD_IPA_RM_RELEASED:
2678 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
2679 break;
2680 }
2681
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302682 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002683
2684 ret = ipa_rm_inactivity_timer_request_resource(
2685 IPA_RM_RESOURCE_WLAN_PROD);
2686
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302687 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002688 if (ret == 0) {
2689 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
2690 hdd_ipa->stats.num_rm_grant_imm++;
2691 }
2692
2693 cancel_delayed_work(&hdd_ipa->wake_lock_work);
2694 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302695 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002696 WIFI_POWER_EVENT_WAKELOCK_IPA);
2697 hdd_ipa->wake_lock_released = false;
2698 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302699 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002700
2701 return ret;
2702}
2703
2704/**
2705 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
2706 * @hdd_ipa: Global HDD IPA context
2707 *
2708 * Return: 0 if resources released, negative errno otherwise
2709 */
2710static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
2711{
2712 int ret = 0;
2713
2714 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2715 return 0;
2716
2717 if (atomic_read(&hdd_ipa->tx_ref_cnt))
2718 return -EAGAIN;
2719
2720 spin_lock_bh(&hdd_ipa->q_lock);
2721 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
2722 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
2723 spin_unlock_bh(&hdd_ipa->q_lock);
2724 return -EAGAIN;
2725 }
2726 spin_unlock_bh(&hdd_ipa->q_lock);
2727
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302728 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002729
Nirav Shahcbc6d722016-03-01 16:24:53 +05302730 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302731 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732 return -EAGAIN;
2733 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302734 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002735
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302736 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002737 switch (hdd_ipa->rm_state) {
2738 case HDD_IPA_RM_GRANTED:
2739 break;
2740 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302741 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742 return -EINPROGRESS;
2743 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302744 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002745 return 0;
2746 }
2747
2748 /* IPA driver returns immediately so set the state here to avoid any
2749 * race condition.
2750 */
2751 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
2752 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302753 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002754
2755 ret =
2756 ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
2757
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302758 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002759 if (unlikely(ret != 0)) {
2760 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
2761 WARN_ON(1);
2762 }
2763
2764 /*
2765 * If wake_lock is released immediately, kernel would try to suspend
2766 * immediately as well, Just avoid ping-pong between suspend-resume
2767 * while there is healthy amount of data transfer going on by
2768 * releasing the wake_lock after some delay.
2769 */
2770 schedule_delayed_work(&hdd_ipa->wake_lock_work,
2771 msecs_to_jiffies
2772 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
2773
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302774 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002775
2776 return ret;
2777}
2778
2779/**
2780 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
2781 * @user_data: user data registered with IPA
2782 * @event: the IPA resource manager event that occurred
2783 * @data: the data associated with the event
2784 *
2785 * Return: None
2786 */
2787static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
2788 unsigned long data)
2789{
2790 struct hdd_ipa_priv *hdd_ipa = user_data;
2791
2792 if (unlikely(!hdd_ipa))
2793 return;
2794
2795 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2796 return;
2797
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302798 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002799
2800 switch (event) {
2801 case IPA_RM_RESOURCE_GRANTED:
2802 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2803 /* RM Notification comes with ISR context
2804 * it should be serialized into work queue to avoid
2805 * ISR sleep problem
2806 */
2807 hdd_ipa->uc_rm_work.event = event;
2808 schedule_work(&hdd_ipa->uc_rm_work.work);
2809 break;
2810 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302811 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002812 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302813 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002814 hdd_ipa->stats.num_rm_grant++;
2815 break;
2816
2817 case IPA_RM_RESOURCE_RELEASED:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302818 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002819 hdd_ipa->resource_unloading = false;
2820 break;
2821
2822 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302823 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002824 break;
2825 }
2826}
2827
2828/**
2829 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
2830 *
2831 * Callback function registered with IPA that is called when IPA wants
2832 * to release the WLAN consumer resource
2833 *
2834 * Return: 0 if the request is granted, negative errno otherwise
2835 */
2836static int hdd_ipa_rm_cons_release(void)
2837{
2838 return 0;
2839}
2840
2841/**
2842 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
2843 *
2844 * Callback function registered with IPA that is called when IPA wants
2845 * to access the WLAN consumer resource
2846 *
2847 * Return: 0 if the request is granted, negative errno otherwise
2848 */
2849static int hdd_ipa_rm_cons_request(void)
2850{
Yun Park4d8b60a2015-10-22 13:59:32 -07002851 int ret = 0;
2852
2853 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302854 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07002855 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002856 __func__);
2857 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07002858 ret = -EINPROGRESS;
2859 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302860 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07002861 "%s: IPA resource unloading in progress",
2862 __func__);
2863 ghdd_ipa->pending_cons_req = true;
2864 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002865 }
Yun Park4d8b60a2015-10-22 13:59:32 -07002866
2867 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002868}
2869
2870/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002871 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002872 * @hdd_ctx: Global HDD context
2873 * @tx_packets: Number of packets transmitted in the last sample period
2874 * @rx_packets: Number of packets received in the last sample period
2875 *
2876 * Return: 0 on success, negative errno on error
2877 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002878static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002879 uint64_t rx_packets)
2880{
2881 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002882 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002883 struct ipa_rm_perf_profile profile;
2884 int ret;
2885
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002886 if (wlan_hdd_validate_context(hdd_ctx))
2887 return 0;
2888
2889 hdd_ipa = hdd_ctx->hdd_ipa;
2890
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002891 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
2892 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
2893 return 0;
2894
2895 memset(&profile, 0, sizeof(profile));
2896
2897 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
2898 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
2899 else if (tx_packets >
2900 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
2901 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
2902 else
2903 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
2904
2905 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
2906 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
2907 else if (rx_packets >
2908 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
2909 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
2910 else
2911 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
2912
Yun Park8f289c82016-10-18 16:38:21 -07002913 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002914 "CONS perf curr: %d, next: %d",
2915 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Park8f289c82016-10-18 16:38:21 -07002916 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002917 "PROD perf curr: %d, next: %d",
2918 hdd_ipa->curr_prod_bw, next_prod_bw);
2919
2920 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08002921 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002922 hdd_ipa->curr_cons_bw, next_cons_bw);
2923 profile.max_supported_bandwidth_mbps = next_cons_bw;
2924 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
2925 &profile);
2926 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08002927 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002928
2929 return ret;
2930 }
2931 hdd_ipa->curr_cons_bw = next_cons_bw;
2932 hdd_ipa->stats.num_cons_perf_req++;
2933 }
2934
2935 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08002936 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002937 hdd_ipa->curr_prod_bw, next_prod_bw);
2938 profile.max_supported_bandwidth_mbps = next_prod_bw;
2939 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
2940 &profile);
2941 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08002942 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002943 return ret;
2944 }
2945 hdd_ipa->curr_prod_bw = next_prod_bw;
2946 hdd_ipa->stats.num_prod_perf_req++;
2947 }
2948
2949 return 0;
2950}
2951
2952/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002953 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
2954 * @hdd_ctx: Global HDD context
2955 * @tx_packets: Number of packets transmitted in the last sample period
2956 * @rx_packets: Number of packets received in the last sample period
2957 *
2958 * Return: 0 on success, negative errno on error
2959 */
2960int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
2961 uint64_t rx_packets)
2962{
2963 int ret;
2964
2965 cds_ssr_protect(__func__);
2966 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
2967 cds_ssr_unprotect(__func__);
2968
2969 return ret;
2970}
2971
2972/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002973 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
2974 * @work: struct work_struct
2975 * @work_handler: work_handler
2976 *
2977 * Return: none
2978 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002979static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
2980 work_func_t work_handler)
2981{
2982 INIT_WORK(work, work_handler);
2983}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002984
2985/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002986 * hdd_ipa_setup_rm() - Setup IPA resource management
2987 * @hdd_ipa: Global HDD IPA context
2988 *
2989 * Return: 0 on success, negative errno on error
2990 */
2991static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
2992{
2993 struct ipa_rm_create_params create_params = { 0 };
2994 int ret;
2995
2996 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2997 return 0;
2998
Rajeev Kumar217f2172016-01-06 18:11:55 -08002999 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3000 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003001 memset(&create_params, 0, sizeof(create_params));
3002 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3003 create_params.reg_params.user_data = hdd_ipa;
3004 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3005 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3006
3007 ret = ipa_rm_create_resource(&create_params);
3008 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303009 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003010 "Create RM resource failed: %d", ret);
3011 goto setup_rm_fail;
3012 }
3013
3014 memset(&create_params, 0, sizeof(create_params));
3015 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3016 create_params.request_resource = hdd_ipa_rm_cons_request;
3017 create_params.release_resource = hdd_ipa_rm_cons_release;
3018 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3019
3020 ret = ipa_rm_create_resource(&create_params);
3021 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303022 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003023 "Create RM CONS resource failed: %d", ret);
3024 goto delete_prod;
3025 }
3026
3027 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3028 IPA_RM_RESOURCE_APPS_CONS);
3029
3030 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3031 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3032 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303033 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003034 ret);
3035 goto timer_init_failed;
3036 }
3037
3038 /* Set the lowest bandwidth to start with */
3039 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3040
3041 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303042 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003043 "Set perf level failed: %d", ret);
3044 goto set_perf_failed;
3045 }
3046
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303047 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003048 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3049 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303050 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003051 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3052 hdd_ipa->wake_lock_released = true;
3053 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3054
3055 return ret;
3056
3057set_perf_failed:
3058 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3059
3060timer_init_failed:
3061 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3062
3063delete_prod:
3064 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3065
3066setup_rm_fail:
3067 return ret;
3068}
3069
3070/**
3071 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3072 * @hdd_ipa: Global HDD IPA context
3073 *
3074 * Destroys all resources associated with the IPA resource manager
3075 *
3076 * Return: None
3077 */
3078static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3079{
3080 int ret;
3081
3082 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3083 return;
3084
3085 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303086 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003087
3088#ifdef WLAN_OPEN_SOURCE
3089 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
3090#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303091 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003092
3093 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3094
3095 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3096 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303097 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003098 "RM PROD resource delete failed %d", ret);
3099
3100 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3101 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303102 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003103 "RM CONS resource delete failed %d", ret);
3104}
3105
3106/**
3107 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3108 * @skb: network buffer
3109 * @adapter: network adapter
3110 *
3111 * Called when a network buffer is received which should not be routed
3112 * to the IPA module.
3113 *
3114 * Return: None
3115 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303116static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003117 hdd_adapter_t *adapter)
3118{
3119 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3120 unsigned int cpu_index;
3121
3122 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303123 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003124 adapter);
3125 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003126 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003127 return;
3128 }
3129
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003130 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003131 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003132 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003133 return;
3134 }
3135
3136 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3137 skb->dev = adapter->dev;
3138 skb->protocol = eth_type_trans(skb, skb->dev);
3139 skb->ip_summed = CHECKSUM_NONE;
3140
3141 cpu_index = wlan_hdd_get_cpu();
3142
3143 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
3144 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
3145 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3146 else
3147 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3148
3149 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
3150 adapter->dev->last_rx = jiffies;
3151}
3152
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003153/**
Leo Chang69c39692016-10-12 20:11:12 -07003154 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3155 * @hdd_ipa: pointer to hdd ipa context
3156 * @adapter: network adapter
3157 * @skb: data pointer
3158 *
3159 * if exception packet has set forward bit, copied new packet should be
3160 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3161 * put into pm queue and tx procedure will be differed
3162 *
3163 * Return: None
3164 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003165static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
3166 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003167{
Leo Chang69c39692016-10-12 20:11:12 -07003168 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3169
Leo Chang69c39692016-10-12 20:11:12 -07003170 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
3171 /* WLAN subsystem is in suspend, put int queue */
3172 if (hdd_ipa->suspended) {
3173 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3174 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3175 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003176 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3177 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003178 pm_tx_cb->exception = true;
3179 pm_tx_cb->adapter = adapter;
3180 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003181 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003182 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3183 hdd_ipa->stats.num_tx_queued++;
3184 } else {
3185 /* Resume, put packet into WLAN TX */
3186 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003187 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003188 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3189 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003190 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003191 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003192 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003193 hdd_ipa->ipa_tx_forward++;
3194 }
3195 }
3196}
3197
3198/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003199 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3200 * @hdd_ipa: pointer to HDD IPA struct
3201 * @adapter: hdd adapter pointer
3202 * @desc: Firmware descriptor
3203 * @skb: Data buffer
3204 *
3205 * Return:
3206 * HDD_IPA_FORWARD_PKT_NONE
3207 * HDD_IPA_FORWARD_PKT_DISCARD
3208 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3209 *
3210 */
3211
3212static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3213 struct hdd_ipa_priv *hdd_ipa,
3214 hdd_adapter_t *adapter,
3215 uint8_t desc,
3216 qdf_nbuf_t skb)
3217{
3218 int ret = HDD_IPA_FORWARD_PKT_NONE;
3219
3220 if ((desc & FW_RX_DESC_FORWARD_M)) {
3221 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3222 "Forward packet to Tx (fw_desc=%d)", desc);
3223 hdd_ipa->ipa_tx_forward++;
3224
3225 if ((desc & FW_RX_DESC_DISCARD_M)) {
3226 hdd_ipa_forward(hdd_ipa, adapter, skb);
3227 hdd_ipa->ipa_rx_internel_drop_count++;
3228 hdd_ipa->ipa_rx_discard++;
3229 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3230 } else {
3231 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
3232 if (cloned_skb)
3233 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3234 else
3235 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3236 "%s: tx skb alloc failed",
3237 __func__);
3238 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3239 }
3240 }
3241
3242 return ret;
3243}
3244
3245/**
Leo Chang69c39692016-10-12 20:11:12 -07003246 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003247 * @priv: pointer to private data registered with IPA (we register a
3248 * pointer to the global IPA context)
3249 * @evt: the IPA event which triggered the callback
3250 * @data: data associated with the event
3251 *
3252 * Return: None
3253 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003254static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003255 unsigned long data)
3256{
3257 struct hdd_ipa_priv *hdd_ipa = NULL;
3258 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303259 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003260 uint8_t iface_id;
3261 uint8_t session_id;
3262 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003263 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003264 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003265
3266 hdd_ipa = (struct hdd_ipa_priv *)priv;
3267
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003268 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3269 return;
3270
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003271 switch (evt) {
3272 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303273 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003274
3275 /*
3276 * When SSR is going on or driver is unloading,
3277 * just drop the packets.
3278 */
3279 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
3280 if (0 != status) {
3281 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3282 "Invalid context: drop packet");
3283 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3284 kfree_skb(skb);
3285 return;
3286 }
3287
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003288 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3289 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003290 iface_id = hdd_ipa->vdev_to_iface[session_id];
Govind Singhb6a89772016-08-12 11:23:35 +05303291 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003292 "IPA_RECEIVE: session_id=%u, iface_id=%u",
3293 session_id, iface_id);
3294 } else {
3295 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
3296 }
3297
3298 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303299 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003300 "IPA_RECEIVE: Invalid iface_id: %u",
3301 iface_id);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303302 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_INFO_HIGH,
Yun Parkb187d542016-11-14 18:10:04 -08003303 "w2i -- skb",
3304 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003305 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003306 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003307 return;
3308 }
3309
3310 iface_context = &hdd_ipa->iface_context[iface_id];
3311 adapter = iface_context->adapter;
3312
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303313 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003314 "w2i -- skb",
3315 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003316 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3317 hdd_ipa->stats.num_rx_excep++;
3318 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
3319 } else {
3320 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
3321 }
3322
3323 iface_context->stats.num_rx_ipa_excep++;
3324
3325 /* Disable to forward Intra-BSS Rx packets when
3326 * ap_isolate=1 in hostapd.conf
3327 */
Yun Park046101c2016-09-02 15:32:14 -07003328 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003329 /*
3330 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3331 * all Rx packets to IPA uC, which need to be forwarded
3332 * to other interface.
3333 * And, IPA driver will send back to WLAN host driver
3334 * through exception pipe with fw_desc field set by FW.
3335 * Here we are checking fw_desc field for FORWARD bit
3336 * set, and forward to Tx. Then copy to kernel stack
3337 * only when DISCARD bit is not set.
3338 */
3339 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003340 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3341 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3342 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003343 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003344 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303345 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003346 "Intra-BSS FWD is disabled-skip forward to Tx");
3347 }
3348
3349 hdd_ipa_send_skb_to_network(skb, adapter);
3350 break;
3351
3352 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303353 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003354 "w2i cb wrong event: 0x%x", evt);
3355 return;
3356 }
3357}
3358
3359/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003360 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3361 * @priv: pointer to private data registered with IPA (we register a
3362 * pointer to the global IPA context)
3363 * @evt: the IPA event which triggered the callback
3364 * @data: data associated with the event
3365 *
3366 * Return: None
3367 */
3368static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3369 unsigned long data)
3370{
3371 cds_ssr_protect(__func__);
3372 __hdd_ipa_w2i_cb(priv, evt, data);
3373 cds_ssr_unprotect(__func__);
3374}
3375
3376/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003377 * hdd_ipa_nbuf_cb() - IPA TX complete callback
3378 * @skb: packet buffer which was transmitted
3379 *
3380 * Return: None
3381 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303382void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003383{
3384 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3385
Govind Singhb6a89772016-08-12 11:23:35 +05303386 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05303387 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003388 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303389 ipa_free_skb((struct ipa_rx_data *)
3390 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003391
3392 hdd_ipa->stats.num_tx_comp_cnt++;
3393
3394 atomic_dec(&hdd_ipa->tx_ref_cnt);
3395
3396 hdd_ipa_rm_try_release(hdd_ipa);
3397}
3398
3399/**
3400 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
3401 * @iface_context: interface-specific IPA context
3402 * @ipa_tx_desc: packet data descriptor
3403 *
3404 * Return: None
3405 */
3406static void hdd_ipa_send_pkt_to_tl(
3407 struct hdd_ipa_iface_context *iface_context,
3408 struct ipa_rx_data *ipa_tx_desc)
3409{
3410 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003411 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303412 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303414 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003415 adapter = iface_context->adapter;
3416 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303417 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418 ipa_free_skb(ipa_tx_desc);
3419 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303420 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421 hdd_ipa_rm_try_release(hdd_ipa);
3422 return;
3423 }
3424
3425 /*
3426 * During CAC period, data packets shouldn't be sent over the air so
3427 * drop all the packets here
3428 */
3429 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
3430 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303431 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003432 iface_context->stats.num_tx_cac_drop++;
3433 hdd_ipa_rm_try_release(hdd_ipa);
3434 return;
3435 }
3436
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003437 ++adapter->stats.tx_packets;
3438
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303439 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003440
3441 skb = ipa_tx_desc->skb;
3442
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303443 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303444 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003445 /* FIXME: This is broken. No such field in cb any more:
3446 NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb; */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003447 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05303448 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003449 ipa_tx_desc->dma_addr
3450 + HDD_IPA_WLAN_FRAG_HEADER
3451 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452 ipa_tx_desc->skb->len -=
3453 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
3454 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05303455 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003456
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003457 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303458 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003459
3460 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
3461
Leo Changfdb45c32016-10-28 11:09:23 -07003462 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
3463 iface_context->tl_context, ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003464 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303465 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003466 ipa_free_skb(ipa_tx_desc);
3467 iface_context->stats.num_tx_err++;
3468 hdd_ipa_rm_try_release(hdd_ipa);
3469 return;
3470 }
3471
3472 atomic_inc(&hdd_ipa->tx_ref_cnt);
3473
3474 iface_context->stats.num_tx++;
3475
3476}
3477
3478/**
Leo Chang11545d62016-10-17 14:53:50 -07003479 * hdd_ipa_is_present() - get IPA hw status
3480 * @hdd_ctx: pointer to hdd context
3481 *
3482 * ipa_uc_reg_rdyCB is not directly designed to check
3483 * ipa hw status. This is an undocumented function which
3484 * has confirmed with IPA team.
3485 *
3486 * Return: true - ipa hw present
3487 * false - ipa hw not present
3488 */
3489bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
3490{
3491 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07003492 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07003493 return true;
3494 else
3495 return false;
3496}
3497
3498/**
Leo Chang69c39692016-10-12 20:11:12 -07003499 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003500 * @work: pointer to the scheduled work
3501 *
3502 * Called during PM resume to send packets to TL which were queued
3503 * while host was in the process of suspending.
3504 *
3505 * Return: None
3506 */
Leo Chang69c39692016-10-12 20:11:12 -07003507static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003508{
3509 struct hdd_ipa_priv *hdd_ipa = container_of(work,
3510 struct hdd_ipa_priv,
3511 pm_work);
3512 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303513 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003514 uint32_t dequeued = 0;
3515
Leo Chang69c39692016-10-12 20:11:12 -07003516 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
3517 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303518 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303519 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
3520 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303521 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003522
3523 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07003525 if (pm_tx_cb->exception) {
3526 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3527 "FLUSH EXCEPTION");
3528 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
3529 } else {
3530 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003531 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07003532 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303533 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003534 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303535 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07003536 qdf_wake_lock_release(&hdd_ipa->wake_lock,
3537 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003538
3539 hdd_ipa->stats.num_tx_dequeued += dequeued;
3540 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
3541 hdd_ipa->stats.num_max_pm_queue = dequeued;
3542}
3543
3544/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003545 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003546 * @priv: pointer to private data registered with IPA (we register a
3547 * pointer to the interface-specific IPA context)
3548 * @evt: the IPA event which triggered the callback
3549 * @data: data associated with the event
3550 *
3551 * Return: None
3552 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003553static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003554 unsigned long data)
3555{
3556 struct hdd_ipa_priv *hdd_ipa = NULL;
3557 struct ipa_rx_data *ipa_tx_desc;
3558 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303559 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003560 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303561 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003562
Mukul Sharma81661ae2015-10-30 20:26:02 +05303563 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003564 ipa_tx_desc = (struct ipa_rx_data *)data;
3565 hdd_ipa = iface_context->hdd_ipa;
3566
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003567 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003568 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
3569 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003570 iface_context->stats.num_tx_drop++;
3571 return;
3572 }
3573
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003574 /*
3575 * When SSR is going on or driver is unloading, just drop the packets.
3576 * During SSR, there is no use in queueing the packets as STA has to
3577 * connect back any way
3578 */
3579 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303580 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003581 ipa_free_skb(ipa_tx_desc);
3582 iface_context->stats.num_tx_drop++;
3583 return;
3584 }
3585
3586 skb = ipa_tx_desc->skb;
3587
Yun Parkb187d542016-11-14 18:10:04 -08003588 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
3589 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590
3591 /*
3592 * If PROD resource is not requested here then there may be cases where
3593 * IPA hardware may be clocked down because of not having proper
3594 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
3595 * workaround to request PROD resource while data is going over CONS
3596 * pipe to prevent the IPA hardware clockdown.
3597 */
3598 hdd_ipa_rm_request(hdd_ipa);
3599
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303600 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003601 /*
3602 * If host is still suspended then queue the packets and these will be
3603 * drained later when resume completes. When packet is arrived here and
3604 * host is suspended, this means that there is already resume is in
3605 * progress.
3606 */
3607 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303608 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003609 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
3610 pm_tx_cb->iface_context = iface_context;
3611 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303612 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 hdd_ipa->stats.num_tx_queued++;
3614
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303615 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003616 return;
3617 }
3618
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303619 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003620
3621 /*
3622 * If we are here means, host is not suspended, wait for the work queue
3623 * to finish.
3624 */
3625#ifdef WLAN_OPEN_SOURCE
3626 flush_work(&hdd_ipa->pm_work);
3627#endif
3628
3629 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
3630}
3631
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003632/*
3633 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
3634 * @priv: pointer to private data registered with IPA (we register a
3635 * pointer to the interface-specific IPA context)
3636 * @evt: the IPA event which triggered the callback
3637 * @data: data associated with the event
3638 *
3639 * Return: None
3640 */
3641static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
3642 unsigned long data)
3643{
3644 cds_ssr_protect(__func__);
3645 __hdd_ipa_i2w_cb(priv, evt, data);
3646 cds_ssr_unprotect(__func__);
3647}
3648
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003649/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003650 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003651 * @hdd_ctx: Global HDD context
3652 *
3653 * Return: 0 on success, negativer errno on error
3654 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003655static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003656{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003657 struct hdd_ipa_priv *hdd_ipa;
3658
3659 if (wlan_hdd_validate_context(hdd_ctx))
3660 return 0;
3661
3662 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003663
3664 if (!hdd_ipa_is_enabled(hdd_ctx))
3665 return 0;
3666
3667 /*
3668 * Check if IPA is ready for suspend, If we are here means, there is
3669 * high chance that suspend would go through but just to avoid any race
3670 * condition after suspend started, these checks are conducted before
3671 * allowing to suspend.
3672 */
3673 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3674 return -EAGAIN;
3675
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303676 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003677
3678 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303679 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003680 return -EAGAIN;
3681 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303682 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003683
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303684 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003685 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303686 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003687
3688 return 0;
3689}
3690
3691/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003692 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
3693 * @hdd_ctx: Global HDD context
3694 *
3695 * Return: 0 on success, negativer errno on error
3696 */
3697int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
3698{
3699 int ret;
3700
3701 cds_ssr_protect(__func__);
3702 ret = __hdd_ipa_suspend(hdd_ctx);
3703 cds_ssr_unprotect(__func__);
3704
3705 return ret;
3706}
3707
3708/**
3709 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003710 * hdd_ctx: Global HDD context
3711 *
3712 * Return: 0 on success, negative errno on error
3713 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003714static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003715{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003716 struct hdd_ipa_priv *hdd_ipa;
3717
3718 if (wlan_hdd_validate_context(hdd_ctx))
3719 return 0;
3720
3721 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003722
3723 if (!hdd_ipa_is_enabled(hdd_ctx))
3724 return 0;
3725
3726 schedule_work(&hdd_ipa->pm_work);
3727
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303728 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003729 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303730 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731
3732 return 0;
3733}
3734
3735/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003736 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
3737 * hdd_ctx: Global HDD context
3738 *
3739 * Return: 0 on success, negative errno on error
3740 */
3741int hdd_ipa_resume(hdd_context_t *hdd_ctx)
3742{
3743 int ret;
3744
3745 cds_ssr_protect(__func__);
3746 ret = __hdd_ipa_resume(hdd_ctx);
3747 cds_ssr_unprotect(__func__);
3748
3749 return ret;
3750}
3751
3752/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003753 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
3754 * @hdd_ipa: Global HDD IPA context
3755 *
3756 * Return: 0 on success, negative errno on error
3757 */
3758static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
3759{
3760 int i, ret = 0;
3761 struct ipa_sys_connect_params *ipa;
3762 uint32_t desc_fifo_sz;
3763
3764 /* The maximum number of descriptors that can be provided to a BAM at
3765 * once is one less than the total number of descriptors that the buffer
3766 * can contain.
3767 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
3768 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
3769 * be provided at once.
3770 * Because of above requirement, one extra descriptor will be added to
3771 * make sure hardware always has one descriptor.
3772 */
3773 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
3774 + sizeof(struct sps_iovec);
3775
3776 /*setup TX pipes */
3777 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3778 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
3779
3780 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
3781 ipa->desc_fifo_sz = desc_fifo_sz;
3782 ipa->priv = &hdd_ipa->iface_context[i];
3783 ipa->notify = hdd_ipa_i2w_cb;
3784
3785 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
3786 ipa->ipa_ep_cfg.hdr.hdr_len =
3787 HDD_IPA_UC_WLAN_TX_HDR_LEN;
3788 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3789 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
3790 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
3791 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
3792 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
3793 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
3794 } else {
3795 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
3796 }
3797 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
3798
3799 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3800 ipa->keep_ipa_awake = 1;
3801
3802 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
3803 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303804 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003805 " ret: %d", i, ret);
3806 goto setup_sys_pipe_fail;
3807 }
3808 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
3809 }
3810
3811 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
3812 /*
3813 * Hard code it here, this can be extended if in case
3814 * PROD pipe is also per interface.
3815 * Right now there is no advantage of doing this.
3816 */
3817 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
3818
3819 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
3820
3821 ipa->client = hdd_ipa->prod_client;
3822
3823 ipa->desc_fifo_sz = desc_fifo_sz;
3824 ipa->priv = hdd_ipa;
3825 ipa->notify = hdd_ipa_w2i_cb;
3826
3827 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3828 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
3829 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
3830 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
3831
3832 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3833 ipa->keep_ipa_awake = 1;
3834
3835 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
3836 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303837 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003838 "Failed for RX pipe: %d", ret);
3839 goto setup_sys_pipe_fail;
3840 }
3841 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
3842 }
3843
3844 return ret;
3845
3846setup_sys_pipe_fail:
3847
3848 while (--i >= 0) {
3849 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303850 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003851 sizeof(struct hdd_ipa_sys_pipe));
3852 }
3853
3854 return ret;
3855}
3856
3857/**
3858 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
3859 * @hdd_ipa: Global HDD IPA context
3860 *
3861 * Return: None
3862 */
3863static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
3864{
3865 int ret = 0, i;
3866 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
3867 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
3868 ret =
3869 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
3870 conn_hdl);
3871 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303872 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003873 ret);
3874
3875 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
3876 }
3877 }
3878}
3879
3880/**
3881 * hdd_ipa_register_interface() - register IPA interface
3882 * @hdd_ipa: Global IPA context
3883 * @iface_context: Per-interface IPA context
3884 *
3885 * Return: 0 on success, negative errno on error
3886 */
3887static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
3888 struct hdd_ipa_iface_context
3889 *iface_context)
3890{
3891 struct ipa_tx_intf tx_intf;
3892 struct ipa_rx_intf rx_intf;
3893 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
3894 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
3895 char *ifname = iface_context->adapter->dev->name;
3896
3897 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
3898 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
3899
3900 int num_prop = 1;
3901 int ret = 0;
3902
3903 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
3904 num_prop++;
3905
3906 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
3907 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303908 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003909 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303910 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003911 goto register_interface_fail;
3912 }
3913
3914 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
3915 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303916 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003917 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303918 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003919 goto register_interface_fail;
3920 }
3921
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303922 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
3923 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003924
3925 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
3926 ifname, HDD_IPA_IPV4_NAME_EXT);
3927 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
3928 ifname, HDD_IPA_IPV6_NAME_EXT);
3929
3930 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
3931 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
3932 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3933 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
3934
3935 /*
3936 * Interface ID is 3rd byte in the CLD header. Add the meta data and
3937 * mask to identify the interface in IPA hardware
3938 */
3939 rx_prop[IPA_IP_v4].attrib.meta_data =
3940 htonl(iface_context->adapter->sessionId << 16);
3941 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
3942
3943 rx_intf.num_props++;
3944 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3945 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
3946 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
3947 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3948 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
3949 rx_prop[IPA_IP_v4].attrib.meta_data =
3950 htonl(iface_context->adapter->sessionId << 16);
3951 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
3952
3953 rx_intf.num_props++;
3954 }
3955
3956 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
3957 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3958 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
3959 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
3960 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
3961 IPA_RESOURCE_NAME_MAX);
3962 tx_intf.num_props++;
3963
3964 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3965 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
3966 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3967 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
3968 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
3969 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
3970 IPA_RESOURCE_NAME_MAX);
3971 tx_intf.num_props++;
3972 }
3973
3974 tx_intf.prop = tx_prop;
3975 rx_intf.prop = rx_prop;
3976
3977 /* Call the ipa api to register interface */
3978 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
3979
3980register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303981 qdf_mem_free(tx_prop);
3982 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003983 return ret;
3984}
3985
3986/**
3987 * hdd_remove_ipa_header() - Remove a specific header from IPA
3988 * @name: Name of the header to be removed
3989 *
3990 * Return: None
3991 */
3992static void hdd_ipa_remove_header(char *name)
3993{
3994 struct ipa_ioc_get_hdr hdrlookup;
3995 int ret = 0, len;
3996 struct ipa_ioc_del_hdr *ipa_hdr;
3997
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303998 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003999 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
4000 ret = ipa_get_hdr(&hdrlookup);
4001 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304002 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004003 name, ret);
4004 return;
4005 }
4006
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304007 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004008 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304009 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004010 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304011 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012 return;
4013 }
4014 ipa_hdr->num_hdls = 1;
4015 ipa_hdr->commit = 0;
4016 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
4017 ipa_hdr->hdl[0].status = -1;
4018 ret = ipa_del_hdr(ipa_hdr);
4019 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304020 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004021 ret);
4022
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304023 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004024}
4025
4026/**
Yun Parkb187d542016-11-14 18:10:04 -08004027 * wlan_ipa_add_hdr() - Add IPA Tx header
4028 * @ipa_hdr: pointer to IPA header addition parameters
4029 *
4030 * Call IPA API to add IPA Tx header descriptor
4031 * and dump Tx header struct
4032 *
4033 * Return: 0 for success, non-zero for failure
4034 */
4035static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
4036{
4037 int ret;
4038
4039 hdd_info("==== IPA Tx Header ====\n"
4040 "name: %s\n"
4041 "hdr_len: %d\n"
4042 "type: %d\n"
4043 "is_partial: %d\n"
4044 "hdr_hdl: 0x%x\n"
4045 "status: %d\n"
4046 "is_eth2_ofst_valid: %d\n"
4047 "eth2_ofst: %d\n",
4048 ipa_hdr->hdr[0].name,
4049 ipa_hdr->hdr[0].hdr_len,
4050 ipa_hdr->hdr[0].type,
4051 ipa_hdr->hdr[0].is_partial,
4052 ipa_hdr->hdr[0].hdr_hdl,
4053 ipa_hdr->hdr[0].status,
4054 ipa_hdr->hdr[0].is_eth2_ofst_valid,
4055 ipa_hdr->hdr[0].eth2_ofst);
4056
4057 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:",
4058 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4059
4060 ret = ipa_add_hdr(ipa_hdr);
4061 return ret;
4062}
4063
4064/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004065 * hdd_ipa_add_header_info() - Add IPA header for a given interface
4066 * @hdd_ipa: Global HDD IPA context
4067 * @iface_context: Interface-specific HDD IPA context
4068 * @mac_addr: Interface MAC address
4069 *
4070 * Return: 0 on success, negativer errno value on error
4071 */
4072static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
4073 struct hdd_ipa_iface_context *iface_context,
4074 uint8_t *mac_addr)
4075{
4076 hdd_adapter_t *adapter = iface_context->adapter;
4077 char *ifname;
4078 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
4079 int ret = -EINVAL;
4080 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
4081 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
4082
4083 ifname = adapter->dev->name;
4084
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304085 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004086 ifname, mac_addr);
4087
4088 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304089 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004090 + sizeof(struct ipa_hdr_add));
4091 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304092 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004093 "%s: ipa_hdr allocation failed", ifname);
4094 ret = -ENOMEM;
4095 goto end;
4096 }
4097
4098 ipa_hdr->commit = 0;
4099 ipa_hdr->num_hdrs = 1;
4100
4101 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4102 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4103 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4104 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4105 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304106 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004107 "ifname=%s, vdev_id=%d",
4108 ifname, uc_tx_hdr->ipa_hd.vdev_id);
4109 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4110 ifname, HDD_IPA_IPV4_NAME_EXT);
4111 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
4112 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
4113 ipa_hdr->hdr[0].is_partial = 1;
4114 ipa_hdr->hdr[0].hdr_hdl = 0;
4115 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4116 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4117
Yun Parkb187d542016-11-14 18:10:04 -08004118 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004119 } else {
4120 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4121
4122 /* Set the Source MAC */
4123 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
4124 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4125
4126 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4127 ifname, HDD_IPA_IPV4_NAME_EXT);
4128 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4129 ipa_hdr->hdr[0].is_partial = 1;
4130 ipa_hdr->hdr[0].hdr_hdl = 0;
4131 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4132 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4133
4134 /* Set the type to IPV4 in the header */
4135 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
4136
4137 ret = ipa_add_hdr(ipa_hdr);
4138 }
4139 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304140 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004141 ifname, ret);
4142 goto end;
4143 }
4144
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304145 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4147
4148 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4149 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4150 ifname, HDD_IPA_IPV6_NAME_EXT);
4151
4152 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4153 uc_tx_hdr =
4154 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4155 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004156 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004157 } else {
4158 /* Set the type to IPV6 in the header */
4159 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4160 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004161 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004162 }
4163
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004164 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304165 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004166 "%s: IPv6 add hdr failed: %d", ifname, ret);
4167 goto clean_ipv4_hdr;
4168 }
4169
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304170 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004171 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4172 }
4173
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304174 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004175
4176 return ret;
4177
4178clean_ipv4_hdr:
4179 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4180 ifname, HDD_IPA_IPV4_NAME_EXT);
4181 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
4182end:
4183 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304184 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004185
4186 return ret;
4187}
4188
4189/**
4190 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
4191 * @adapter: Adapter upon which IPA was previously configured
4192 *
4193 * Return: None
4194 */
4195static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
4196{
4197 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4198 int ret;
4199 char name_ipa[IPA_RESOURCE_NAME_MAX];
4200
4201 /* Remove the headers */
4202 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4203 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
4204 hdd_ipa_remove_header(name_ipa);
4205
4206 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4207 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4208 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
4209 hdd_ipa_remove_header(name_ipa);
4210 }
4211 /* unregister the interface with IPA */
4212 ret = ipa_deregister_intf(adapter->dev->name);
4213 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304214 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004215 "%s: ipa_deregister_intf fail: %d",
4216 adapter->dev->name, ret);
4217}
4218
4219/**
4220 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4221 * @iface_context: interface-specific IPA context
4222 *
4223 * Return: None
4224 */
4225static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4226{
4227 if (iface_context == NULL)
4228 return;
4229
4230 hdd_ipa_clean_hdr(iface_context->adapter);
4231
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304232 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004233 iface_context->adapter->ipa_context = NULL;
4234 iface_context->adapter = NULL;
4235 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304236 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004237 iface_context->ifa_address = 0;
4238 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304239 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004240 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304241 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004242 }
4243 iface_context->hdd_ipa->num_iface--;
4244}
4245
4246/**
4247 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4248 * @hdd_ipa: HDD IPA global context
4249 * @adapter: Interface upon which IPA is being setup
4250 * @sta_id: Station ID of the API instance
4251 *
4252 * Return: 0 on success, negative errno value on error
4253 */
4254static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
4255 hdd_adapter_t *adapter, uint8_t sta_id)
4256{
4257 struct hdd_ipa_iface_context *iface_context = NULL;
4258 void *tl_context = NULL;
4259 int i, ret = 0;
4260
4261 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4262 * channel change indication. Since these indications are sent by lower
4263 * layer as SAP updates and IPA doesn't have to do anything for these
4264 * updates so ignoring!
4265 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004266 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004267 return 0;
4268
4269 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4270 if (hdd_ipa->iface_context[i].adapter == NULL) {
4271 iface_context = &(hdd_ipa->iface_context[i]);
4272 break;
4273 }
4274 }
4275
4276 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304277 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004278 "All the IPA interfaces are in use");
4279 ret = -ENOMEM;
4280 goto end;
4281 }
4282
4283 adapter->ipa_context = iface_context;
4284 iface_context->adapter = adapter;
4285 iface_context->sta_id = sta_id;
Leo Changfdb45c32016-10-28 11:09:23 -07004286 tl_context = cdp_peer_get_vdev_by_sta_id(
4287 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004288 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304289 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004290 "Not able to get TL context sta_id: %d", sta_id);
4291 ret = -EINVAL;
4292 goto end;
4293 }
4294
4295 iface_context->tl_context = tl_context;
4296
4297 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
4298 adapter->dev->dev_addr);
4299
4300 if (ret)
4301 goto end;
4302
4303 /* Configure the TX and RX pipes filter rules */
4304 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
4305 if (ret)
4306 goto cleanup_header;
4307
4308 hdd_ipa->num_iface++;
4309 return ret;
4310
4311cleanup_header:
4312
4313 hdd_ipa_clean_hdr(adapter);
4314end:
4315 if (iface_context)
4316 hdd_ipa_cleanup_iface(iface_context);
4317 return ret;
4318}
4319
Yun Parka27049a2016-10-11 12:30:49 -07004320#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004321/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004322 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004323 * @mcc_mode: 0=MCC/1=SCC
4324 *
4325 * Return: 0 on success, negative errno value on error
4326 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004327static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004328{
4329 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304330 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004331 hdd_adapter_t *pAdapter;
4332 struct ipa_msg_meta meta;
4333 struct ipa_wlan_msg *msg;
4334 int ret;
4335
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004336 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004337 return -EINVAL;
4338
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004339 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4340 return -EINVAL;
4341
4342 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004343 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004344 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304345 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004346 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08004347 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004348 pAdapter->device_mode == QDF_SAP_MODE) {
4349 hdd_info("MCC->SCC: Flush TxRx queue(d_mode=%d)",
4350 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004351 hdd_deinit_tx_rx(pAdapter);
4352 }
4353 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004354 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355 adapter_node = next;
4356 }
4357 }
4358
4359 /* Send SCC/MCC Switching event to IPA */
4360 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304361 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004362 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004363 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004364 return -ENOMEM;
4365 }
4366
4367 meta.msg_type = mcc_mode ?
4368 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004369 hdd_info("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370
4371 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4372
4373 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004374 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004375 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304376 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004377 }
4378
4379 return ret;
4380}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004381
4382/**
4383 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4384 * @mcc_mode: 0=MCC/1=SCC
4385 *
4386 * Return: 0 on success, negative errno value on error
4387 */
4388int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
4389{
4390 int ret;
4391
4392 cds_ssr_protect(__func__);
4393 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4394 cds_ssr_unprotect(__func__);
4395
4396 return ret;
4397}
Yun Parka27049a2016-10-11 12:30:49 -07004398#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004399
4400/**
4401 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4402 * @event: IPA WLAN event to be converted to a string
4403 *
4404 * Return: ASCII string representing the IPA WLAN event
4405 */
4406static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4407{
4408 switch (event) {
4409 case WLAN_CLIENT_CONNECT:
4410 return "WLAN_CLIENT_CONNECT";
4411 case WLAN_CLIENT_DISCONNECT:
4412 return "WLAN_CLIENT_DISCONNECT";
4413 case WLAN_CLIENT_POWER_SAVE_MODE:
4414 return "WLAN_CLIENT_POWER_SAVE_MODE";
4415 case WLAN_CLIENT_NORMAL_MODE:
4416 return "WLAN_CLIENT_NORMAL_MODE";
4417 case SW_ROUTING_ENABLE:
4418 return "SW_ROUTING_ENABLE";
4419 case SW_ROUTING_DISABLE:
4420 return "SW_ROUTING_DISABLE";
4421 case WLAN_AP_CONNECT:
4422 return "WLAN_AP_CONNECT";
4423 case WLAN_AP_DISCONNECT:
4424 return "WLAN_AP_DISCONNECT";
4425 case WLAN_STA_CONNECT:
4426 return "WLAN_STA_CONNECT";
4427 case WLAN_STA_DISCONNECT:
4428 return "WLAN_STA_DISCONNECT";
4429 case WLAN_CLIENT_CONNECT_EX:
4430 return "WLAN_CLIENT_CONNECT_EX";
4431
4432 case IPA_WLAN_EVENT_MAX:
4433 default:
4434 return "UNKNOWN";
4435 }
4436}
4437
4438/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004439 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4440 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4441 *
4442 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4443 */
4444static enum ipa_wlan_event
4445hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4446{
4447 enum ipa_wlan_event ipa_event;
4448
4449 switch (hdd_ipa_event_type) {
4450 case HDD_IPA_CLIENT_CONNECT:
4451 ipa_event = WLAN_CLIENT_CONNECT;
4452 break;
4453 case HDD_IPA_CLIENT_DISCONNECT:
4454 ipa_event = WLAN_CLIENT_DISCONNECT;
4455 break;
4456 case HDD_IPA_AP_CONNECT:
4457 ipa_event = WLAN_AP_CONNECT;
4458 break;
4459 case HDD_IPA_AP_DISCONNECT:
4460 ipa_event = WLAN_AP_DISCONNECT;
4461 break;
4462 case HDD_IPA_STA_CONNECT:
4463 ipa_event = WLAN_STA_CONNECT;
4464 break;
4465 case HDD_IPA_STA_DISCONNECT:
4466 ipa_event = WLAN_STA_DISCONNECT;
4467 break;
4468 case HDD_IPA_CLIENT_CONNECT_EX:
4469 ipa_event = WLAN_CLIENT_CONNECT_EX;
4470 break;
4471 case HDD_IPA_WLAN_EVENT_MAX:
4472 default:
4473 ipa_event = IPA_WLAN_EVENT_MAX;
4474 break;
4475 }
4476 return ipa_event;
4477
4478}
4479
4480/**
4481 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004482 * @adapter: adapter upon which the event was received
4483 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004484 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004485 * @mac_address: MAC address associated with the event
4486 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004487 * This function is meant to be called from within wlan_hdd_ipa.c
4488 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004489 * Return: 0 on success, negative errno value on error
4490 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07004491static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004492 enum ipa_wlan_event type, uint8_t *mac_addr)
4493{
4494 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4495 struct ipa_msg_meta meta;
4496 struct ipa_wlan_msg *msg;
4497 struct ipa_wlan_msg_ex *msg_ex = NULL;
4498 int ret;
4499
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304500 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004501 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
4502 mac_addr, sta_id);
4503
4504 if (type >= IPA_WLAN_EVENT_MAX)
4505 return -EINVAL;
4506
4507 if (WARN_ON(is_zero_ether_addr(mac_addr)))
4508 return -EINVAL;
4509
4510 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304511 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512 return -EINVAL;
4513 }
4514
4515 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
4516 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08004517 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004518 return 0;
4519 }
4520
4521 /*
4522 * During IPA UC resource loading/unloading new events can be issued.
4523 * Store the events separately and handle them later.
4524 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004525 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4526 if (hdd_ipa->resource_loading) {
4527 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004528 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08004529
Yun Park7c4f31b2016-11-30 10:09:21 -08004530 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA resource %s inprogress",
4531 hdd_ipa->resource_loading ? "load":"unload");
4532
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004533 hdd_err("IPA resource %s inprogress",
4534 hdd_ipa->resource_loading ? "load":"unload");
Yun Parkf19e07d2015-11-20 11:34:27 -08004535
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004536 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004537
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004538 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4539 if (pending_event_count >= HDD_IPA_MAX_PENDING_EVENT_COUNT) {
4540 hdd_notice("Reached max pending event count");
4541 qdf_list_remove_front(&hdd_ipa->pending_event,
4542 (qdf_list_node_t **)&pending_event);
4543 } else {
4544 pending_event =
4545 (struct ipa_uc_pending_event *)qdf_mem_malloc(
4546 sizeof(struct ipa_uc_pending_event));
4547 }
4548
4549 if (!pending_event) {
Yun Park7c4f31b2016-11-30 10:09:21 -08004550 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4551 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004552 qdf_mutex_release(&hdd_ipa->event_lock);
4553 return -ENOMEM;
4554 }
4555
4556 pending_event->adapter = adapter;
4557 pending_event->sta_id = sta_id;
4558 pending_event->type = type;
4559 qdf_mem_copy(pending_event->mac_addr,
4560 mac_addr,
4561 QDF_MAC_ADDR_SIZE);
4562 qdf_list_insert_back(&hdd_ipa->pending_event,
4563 &pending_event->node);
4564
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304565 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004566 return 0;
4567 } else if (hdd_ipa->resource_unloading) {
4568 hdd_err("%s: IPA resource unload inprogress", __func__);
4569 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004570 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004571 }
4572
4573 hdd_ipa->stats.event[type]++;
4574
Leo Chang3bc8fed2015-11-13 10:59:47 -08004575 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004576 switch (type) {
4577 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004578 qdf_mutex_acquire(&hdd_ipa->event_lock);
4579
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004580 /* STA already connected and without disconnect, connect again
4581 * This is Roaming scenario
4582 */
4583 if (hdd_ipa->sta_connected)
4584 hdd_ipa_cleanup_iface(adapter->ipa_context);
4585
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004586 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4587 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304588 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004589 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004590 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004591
Yun Park8f289c82016-10-18 16:38:21 -07004592 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4593 (hdd_ipa->sap_num_connected_sta > 0) &&
4594 !hdd_ipa->sta_connected) {
4595 qdf_mutex_release(&hdd_ipa->event_lock);
4596 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004597 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004598 qdf_mutex_acquire(&hdd_ipa->event_lock);
4599 }
4600
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004601 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004602 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004603 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004604
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004605 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07004606
4607 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004608 break;
4609
4610 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004611 qdf_mutex_acquire(&hdd_ipa->event_lock);
4612
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 /* For DFS channel we get two start_bss event (before and after
4614 * CAC). Also when ACS range includes both DFS and non DFS
4615 * channels, we could possibly change channel many times due to
4616 * RADAR detection and chosen channel may not be a DFS channels.
4617 * So dont return error here. Just discard the event.
4618 */
Yun Park8f289c82016-10-18 16:38:21 -07004619 if (adapter->ipa_context) {
4620 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004621 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07004622 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004624 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4625 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004626 hdd_err("%s: Evt: %d, Interface setup failed",
4627 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304628 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004629 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004630 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004631
Yun Park8f289c82016-10-18 16:38:21 -07004632 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4633 qdf_mutex_release(&hdd_ipa->event_lock);
4634 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004635 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004636 qdf_mutex_acquire(&hdd_ipa->event_lock);
4637 }
4638
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004639 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004641 (adapter->ipa_context))->iface_id;
4642
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304643 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644 break;
4645
4646 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304647 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004648
4649 if (!hdd_ipa->sta_connected) {
Yun Parkb187d542016-11-14 18:10:04 -08004650 hdd_err("%s: Evt: %d, STA already disconnected",
4651 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304652 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004653 return -EINVAL;
4654 }
Yun Parka37592b2016-06-11 17:10:28 -07004655
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004656 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07004657
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08004659 hdd_notice("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004660 msg_ex->name);
4661 } else {
4662 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07004663 if (!hdd_ipa->num_iface &&
4664 (HDD_IPA_UC_NUM_WDI_PIPE ==
4665 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004666 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004667 }
4668
Yun Park74127cf2016-09-18 11:22:41 -07004669 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4670 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07004671 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004672 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004673 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004674 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004675 hdd_ipa->vdev_to_iface[adapter->sessionId] =
4676 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004677 }
4678
Yun Park8f289c82016-10-18 16:38:21 -07004679 hdd_ipa_cleanup_iface(adapter->ipa_context);
4680
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304681 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004682 break;
4683
4684 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004685 qdf_mutex_acquire(&hdd_ipa->event_lock);
4686
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004687 if (!adapter->ipa_context) {
Yun Parkb187d542016-11-14 18:10:04 -08004688 hdd_err("%s: Evt: %d, SAP already disconnected",
4689 msg_ex->name, meta.msg_type);
Yun Park8f289c82016-10-18 16:38:21 -07004690 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004691 return -EINVAL;
4692 }
4693
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004694 if ((!hdd_ipa->num_iface) &&
4695 (HDD_IPA_UC_NUM_WDI_PIPE ==
4696 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004697 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004698 /*
4699 * We disable WDI pipes directly here since
4700 * IPA_OPCODE_TX/RX_SUSPEND message will not be
4701 * processed when unloading WLAN driver is in
4702 * progress
4703 */
4704 hdd_ipa_uc_disable_pipes(hdd_ipa);
4705 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304706 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707 "NO INTF left but still pipe clean up");
4708 hdd_ipa_uc_handle_last_discon(hdd_ipa);
4709 }
4710 }
4711
4712 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07004713 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004714 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004715 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004716 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004717 hdd_ipa->vdev_to_iface[adapter->sessionId] =
4718 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004719 }
Yun Parka37592b2016-06-11 17:10:28 -07004720
Yun Park8f289c82016-10-18 16:38:21 -07004721 hdd_ipa_cleanup_iface(adapter->ipa_context);
4722
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304723 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004724 break;
4725
4726 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004727 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304728 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004729 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304730 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004731 return 0;
4732 }
4733
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304734 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004735 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
4736 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07004737 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304738 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004739 "%s: STA ID %d found, not valid",
4740 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004741 return 0;
4742 }
Yun Park312f71a2015-12-08 10:22:42 -08004743
4744 /* Enable IPA UC Data PIPEs when first STA connected */
Yun Parka37592b2016-06-11 17:10:28 -07004745 if (0 == hdd_ipa->sap_num_connected_sta) {
4746 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07004747 hdd_ipa->sta_connected) {
4748 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07004749 hdd_ipa_uc_offload_enable_disable(
4750 hdd_get_adapter(hdd_ipa->hdd_ctx,
4751 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004752 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004753 qdf_mutex_acquire(&hdd_ipa->event_lock);
4754 }
Yun Parka37592b2016-06-11 17:10:28 -07004755
Yun Park312f71a2015-12-08 10:22:42 -08004756 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
4757 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304758 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08004759 "%s: handle 1st con ret %d",
4760 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07004761
4762 if (hdd_ipa_uc_sta_is_enabled(
4763 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07004764 hdd_ipa->sta_connected) {
4765 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07004766 hdd_ipa_uc_offload_enable_disable(
4767 hdd_get_adapter(
4768 hdd_ipa->hdd_ctx,
4769 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004770 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004771 } else {
4772 qdf_mutex_release(&hdd_ipa->event_lock);
4773 }
Yun Parka37592b2016-06-11 17:10:28 -07004774
Yun Park312f71a2015-12-08 10:22:42 -08004775 return ret;
4776 }
4777 }
4778
4779 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08004780
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304781 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004782
4783 meta.msg_type = type;
4784 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
4785 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304786 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004787
4788 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304789 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004790 "msg_ex allocation failed");
4791 return -ENOMEM;
4792 }
4793 strlcpy(msg_ex->name, adapter->dev->name,
4794 IPA_RESOURCE_NAME_MAX);
4795 msg_ex->num_of_attribs = 1;
4796 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
4797 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4798 msg_ex->attribs[0].offset =
4799 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4800 } else {
4801 msg_ex->attribs[0].offset =
4802 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4803 }
4804 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
4805 IPA_MAC_ADDR_SIZE);
4806
4807 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
4808
4809 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304810 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304811 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304812 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004813 return ret;
4814 }
4815 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004816 return ret;
4817
4818 case WLAN_CLIENT_DISCONNECT:
4819 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304820 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004821 "%s: IPA UC OFFLOAD NOT ENABLED",
4822 msg_ex->name);
4823 return 0;
4824 }
4825
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304826 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004827 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304828 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004829 "%s: STA ID %d NOT found, not valid",
4830 msg_ex->name, sta_id);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304831 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004832 return 0;
4833 }
4834 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07004835
Yun Park9b5030f2016-11-08 12:02:37 -08004836 /* Disable IPA UC TX PIPE when last STA disconnected */
4837 if (!hdd_ipa->sap_num_connected_sta) {
4838 if ((false == hdd_ipa->resource_unloading)
4839 && (HDD_IPA_UC_NUM_WDI_PIPE ==
4840 hdd_ipa->activated_fw_pipe)) {
4841 hdd_ipa_uc_handle_last_discon(hdd_ipa);
4842 }
4843
Yun Park8f289c82016-10-18 16:38:21 -07004844 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08004845
4846 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4847 hdd_ipa->sta_connected)
4848 hdd_ipa_uc_offload_enable_disable(
4849 hdd_get_adapter(hdd_ipa->hdd_ctx,
4850 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004851 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004852 } else {
4853 qdf_mutex_release(&hdd_ipa->event_lock);
4854 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004855 break;
4856
4857 default:
4858 return 0;
4859 }
4860
4861 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304862 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004863 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304864 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004865 return -ENOMEM;
4866 }
4867
4868 meta.msg_type = type;
4869 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
4870 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
4871
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304872 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004873 msg->name, meta.msg_type);
4874
4875 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4876
4877 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004878 hdd_err("%s: Evt: %d fail:%d",
4879 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304880 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004881 return ret;
4882 }
4883
4884 hdd_ipa->stats.num_send_msg++;
4885
4886end:
4887 return ret;
4888}
4889
4890/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004891 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07004892 * @adapter: adapter upon which the event was received
4893 * @sta_id: station id for the event
4894 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
4895 * @mac_address: MAC address associated with the event
4896 *
4897 * This function is meant to be called from outside of wlan_hdd_ipa.c.
4898 *
4899 * Return: 0 on success, negative errno value on error
4900 */
4901int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
4902 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
4903{
4904 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004905 int ret = 0;
4906
4907 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07004908
Leo Changa202b522016-10-14 16:13:50 -07004909 /* Data path offload only support for STA and SAP mode */
4910 if ((QDF_STA_MODE == adapter->device_mode) ||
4911 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004912 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07004913
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004914 cds_ssr_unprotect(__func__);
4915
4916 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07004917}
4918
4919/**
4920 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
4921 * @hdd_ipa: Global HDD IPA context
4922 *
4923 * Return: None
4924 */
4925static void
4926hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
4927{
4928 unsigned int pending_event_count;
4929 struct ipa_uc_pending_event *pending_event = NULL;
4930
4931 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4932 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4933 "%s, Pending Event Count %d", __func__, pending_event_count);
4934 if (!pending_event_count) {
4935 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4936 "%s, No Pending Event", __func__);
4937 return;
4938 }
4939
4940 qdf_list_remove_front(&hdd_ipa->pending_event,
4941 (qdf_list_node_t **)&pending_event);
4942 while (pending_event != NULL) {
4943 __hdd_ipa_wlan_evt(pending_event->adapter,
4944 pending_event->type,
4945 pending_event->sta_id,
4946 pending_event->mac_addr);
4947 qdf_mem_free(pending_event);
4948 pending_event = NULL;
4949 qdf_list_remove_front(&hdd_ipa->pending_event,
4950 (qdf_list_node_t **)&pending_event);
4951 }
4952}
4953
4954/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004955 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
4956 * @state: IPA RM state value
4957 *
4958 * Return: ASCII string representing the IPA RM state
4959 */
4960static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
4961{
4962 switch (state) {
4963 case HDD_IPA_RM_RELEASED:
4964 return "RELEASED";
4965 case HDD_IPA_RM_GRANT_PENDING:
4966 return "GRANT_PENDING";
4967 case HDD_IPA_RM_GRANTED:
4968 return "GRANTED";
4969 }
4970
4971 return "UNKNOWN";
4972}
4973
4974/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004975 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004976 * @hdd_ctx: HDD global context
4977 *
4978 * Allocate hdd_ipa resources, ipa pipe resource and register
4979 * wlan interface with IPA module.
4980 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304981 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004982 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004983static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004984{
4985 struct hdd_ipa_priv *hdd_ipa = NULL;
4986 int ret, i;
4987 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park7f171ab2016-07-29 15:44:22 -07004988 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004989
4990 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304991 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004992
Yun Park7f171ab2016-07-29 15:44:22 -07004993 if (!pdev) {
4994 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
4995 goto fail_return;
4996 }
4997
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304998 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305000 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005001 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005002 }
5003
5004 hdd_ctx->hdd_ipa = hdd_ipa;
5005 ghdd_ipa = hdd_ipa;
5006 hdd_ipa->hdd_ctx = hdd_ctx;
5007 hdd_ipa->num_iface = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07005008 cdp_ipa_get_resource(cds_get_context(QDF_MODULE_ID_SOC),
5009 cds_get_context(QDF_MODULE_ID_TXRX),
5010 &hdd_ipa->ipa_resource);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08005011 if ((0 == hdd_ipa->ipa_resource.ce_sr_base_paddr) ||
5012 (0 == hdd_ipa->ipa_resource.tx_comp_ring_base_paddr) ||
5013 (0 == hdd_ipa->ipa_resource.rx_rdy_ring_base_paddr) ||
5014 (0 == hdd_ipa->ipa_resource.rx2_rdy_ring_base_paddr)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305015 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Leo Chang3bc8fed2015-11-13 10:59:47 -08005016 "IPA UC resource alloc fail");
5017 goto fail_get_resource;
5018 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005019
5020 /* Create the interface context */
5021 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5022 iface_context = &hdd_ipa->iface_context[i];
5023 iface_context->hdd_ipa = hdd_ipa;
5024 iface_context->cons_client =
5025 hdd_ipa_adapter_2_client[i].cons_client;
5026 iface_context->prod_client =
5027 hdd_ipa_adapter_2_client[i].prod_client;
5028 iface_context->iface_id = i;
5029 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305030 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005031 }
5032 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005033 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5034 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005035 }
5036
Leo Chang69c39692016-10-12 20:11:12 -07005037 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305038 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305039 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005040
5041 ret = hdd_ipa_setup_rm(hdd_ipa);
5042 if (ret)
5043 goto fail_setup_rm;
5044
5045 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5046 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305047 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005048 hdd_ipa->sap_num_connected_sta = 0;
5049 hdd_ipa->ipa_tx_packets_diff = 0;
5050 hdd_ipa->ipa_rx_packets_diff = 0;
5051 hdd_ipa->ipa_p_tx_packets = 0;
5052 hdd_ipa->ipa_p_rx_packets = 0;
5053 hdd_ipa->resource_loading = false;
5054 hdd_ipa->resource_unloading = false;
5055 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005056 hdd_ipa->ipa_pipes_down = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005057 /* Setup IPA sys_pipe for MCC */
5058 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5059 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5060 if (ret)
5061 goto fail_create_sys_pipe;
5062 }
5063 hdd_ipa_uc_ol_init(hdd_ctx);
5064 } else {
5065 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5066 if (ret)
5067 goto fail_create_sys_pipe;
5068 }
5069
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305070 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005071
5072fail_create_sys_pipe:
5073 hdd_ipa_destroy_rm_resource(hdd_ipa);
5074fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305075 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005076fail_get_resource:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305077 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005078 hdd_ctx->hdd_ipa = NULL;
5079 ghdd_ipa = NULL;
5080fail_return:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305081 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005082}
5083
5084/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005085 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5086 * @hdd_ctx: HDD global context
5087 *
5088 * Allocate hdd_ipa resources, ipa pipe resource and register
5089 * wlan interface with IPA module.
5090 *
5091 * Return: QDF_STATUS enumeration
5092 */
5093QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
5094{
5095 QDF_STATUS ret;
5096
5097 cds_ssr_protect(__func__);
5098 ret = __hdd_ipa_init(hdd_ctx);
5099 cds_ssr_unprotect(__func__);
5100
5101 return ret;
5102}
5103
5104/**
Yun Parkf19e07d2015-11-20 11:34:27 -08005105 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
5106 * @hdd_ipa: pointer to HDD IPA struct
5107 *
5108 * Return: none
5109 */
Jeff Johnsond7720632016-10-05 16:04:32 -07005110static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08005111{
5112 struct ipa_uc_pending_event *pending_event = NULL;
5113
Anurag Chouhanffb21542016-02-17 14:33:03 +05305114 while (qdf_list_remove_front(&hdd_ipa->pending_event,
5115 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305116 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005117 }
5118
Anurag Chouhanffb21542016-02-17 14:33:03 +05305119 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005120}
5121
5122/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005123 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005124 * @hdd_ctx: HDD global context
5125 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305126 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005127 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005128static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005129{
5130 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5131 int i;
5132 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305133 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005134 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5135
5136 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305137 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005138
5139 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5140 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5141 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5142 }
5143
5144 /* Teardown IPA sys_pipe for MCC */
5145 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5146 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5147
5148 hdd_ipa_destroy_rm_resource(hdd_ipa);
5149
5150#ifdef WLAN_OPEN_SOURCE
5151 cancel_work_sync(&hdd_ipa->pm_work);
5152#endif
5153
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305154 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005155
Nirav Shahcbc6d722016-03-01 16:24:53 +05305156 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5157 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305158 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005159
5160 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
5161 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
5162
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305163 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005164 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305165 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005166
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305167 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005168
5169 /* destory the interface lock */
5170 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5171 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305172 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005173 }
5174
5175 /* This should never hit but still make sure that there are no pending
5176 * descriptor in IPA hardware
5177 */
5178 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305179 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005180 "IPA Pending write done: %d Waiting!",
5181 hdd_ipa->pending_hw_desc_cnt);
5182
5183 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
5184 usleep_range(100, 100);
5185 }
5186
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305187 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005188 "IPA Pending write done: desc: %d %s(%d)!",
5189 hdd_ipa->pending_hw_desc_cnt,
5190 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
5191 : "leak", i);
5192 }
5193 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
5194 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305195 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305196 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
5197 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005198 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305199 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305200 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
5201 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005202 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305203 qdf_mutex_destroy(&hdd_ipa->event_lock);
5204 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005205 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005206
5207#ifdef WLAN_OPEN_SOURCE
5208 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5209 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5210 hdd_ipa->uc_op_work[i].msg = NULL;
5211 }
5212#endif
5213 }
5214
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305215 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005216 hdd_ctx->hdd_ipa = NULL;
5217
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305218 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005219}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005220
5221/**
5222 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5223 * @hdd_ctx: HDD global context
5224 *
5225 * Return: QDF_STATUS enumeration
5226 */
5227QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
5228{
5229 QDF_STATUS ret;
5230
5231 cds_ssr_protect(__func__);
5232 ret = __hdd_ipa_cleanup(hdd_ctx);
5233 cds_ssr_unprotect(__func__);
5234
5235 return ret;
5236}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005237#endif /* IPA_OFFLOAD */