blob: 677010a468d5e5f0ddb6aa989e0bd6776d1005aa [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
jge62037862016-12-09 10:44:33 +08002 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ipa.c
30 *
31 * WLAN HDD and ipa interface implementation
32 * Originally written by Qualcomm Atheros, Inc
33 */
34
35#ifdef IPA_OFFLOAD
36
37/* Include Files */
Mohit Khannafa99aea2016-05-12 21:43:13 -070038#include <linux/ipa.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039#include <wlan_hdd_includes.h>
40#include <wlan_hdd_ipa.h>
41
42#include <linux/etherdevice.h>
43#include <linux/atomic.h>
44#include <linux/netdevice.h>
45#include <linux/skbuff.h>
46#include <linux/list.h>
47#include <linux/debugfs.h>
48#include <linux/inetdevice.h>
49#include <linux/ip.h>
50#include <wlan_hdd_softap_tx_rx.h>
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +053051#include <ol_txrx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070052#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053
54#include "cds_sched.h"
55
56#include "wma.h"
57#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080058#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
Dhanashri Atreb08959a2016-03-01 17:28:03 -080060#include "cdp_txrx_ipa.h"
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -080061#include <cdp_txrx_handle.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080062#define HDD_IPA_DESC_BUFFER_RATIO 4
63#define HDD_IPA_IPV4_NAME_EXT "_ipv4"
64#define HDD_IPA_IPV6_NAME_EXT "_ipv6"
65
66#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
68/* WDI TX and RX PIPE */
69#define HDD_IPA_UC_NUM_WDI_PIPE 2
70#define HDD_IPA_UC_MAX_PENDING_EVENT 33
71
72#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
73#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
74#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
75#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
76
77#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
78#define HDD_IPA_MAX_IFACE 3
79#define HDD_IPA_MAX_SYSBAM_PIPE 4
80#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
81#define HDD_IPA_ENABLE_MASK BIT(0)
82#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
83#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
84#define HDD_IPA_RM_ENABLE_MASK BIT(3)
85#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
86#define HDD_IPA_UC_ENABLE_MASK BIT(5)
87#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
88#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
89
Yun Parkf19e07d2015-11-20 11:34:27 -080090#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
91
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080092typedef enum {
93 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
94 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
95 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
96 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
97 HDD_IPA_UC_OPCODE_STATS = 4,
Manikandan Mohan153a4c32017-02-16 15:04:30 -080098 HDD_IPA_UC_OPCODE_UC_READY = 8,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080099 /* keep this last */
100 HDD_IPA_UC_OPCODE_MAX
101} hdd_ipa_uc_op_code;
102
103/**
104 * enum - Reason codes for stat query
105 *
106 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
107 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
108 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800109 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800110 */
111enum {
112 HDD_IPA_UC_STAT_REASON_NONE,
113 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -0800114 HDD_IPA_UC_STAT_REASON_BW_CAL,
115 HDD_IPA_UC_STAT_REASON_DUMP_INFO
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800116};
117
118/**
119 * enum hdd_ipa_rm_state - IPA resource manager state
120 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
121 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
122 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
123 */
124enum hdd_ipa_rm_state {
125 HDD_IPA_RM_RELEASED,
126 HDD_IPA_RM_GRANT_PENDING,
127 HDD_IPA_RM_GRANTED,
128};
129
130struct llc_snap_hdr {
131 uint8_t dsap;
132 uint8_t ssap;
133 uint8_t resv[4];
134 __be16 eth_type;
135} __packed;
136
Leo Chang3bc8fed2015-11-13 10:59:47 -0800137/**
138 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
139 * @eth: ether II header
140 * @llc_snap: LLC snap header
141 *
142 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143struct hdd_ipa_tx_hdr {
144 struct ethhdr eth;
145 struct llc_snap_hdr llc_snap;
146} __packed;
147
Leo Chang3bc8fed2015-11-13 10:59:47 -0800148/**
149 * struct frag_header - fragment header type registered to IPA hardware
150 * @length: fragment length
151 * @reserved1: Reserved not used
152 * @reserved2: Reserved not used
153 *
154 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800155struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800156 uint16_t length;
157 uint32_t reserved1;
158 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800159} __packed;
160
Leo Chang3bc8fed2015-11-13 10:59:47 -0800161/**
162 * struct ipa_header - ipa header type registered to IPA hardware
163 * @vdev_id: vdev id
164 * @reserved: Reserved not used
165 *
166 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800167struct ipa_header {
168 uint32_t
169 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
170 reserved:24;
171} __packed;
172
Leo Chang3bc8fed2015-11-13 10:59:47 -0800173/**
174 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
175 * @frag_hd: fragment header
176 * @ipa_hd: ipa header
177 * @eth: ether II header
178 *
179 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800180struct hdd_ipa_uc_tx_hdr {
181 struct frag_header frag_hd;
182 struct ipa_header ipa_hd;
183 struct ethhdr eth;
184} __packed;
185
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186/**
187 * struct hdd_ipa_cld_hdr - IPA CLD Header
188 * @reserved: reserved fields
189 * @iface_id: interface ID
190 * @sta_id: Station ID
191 *
192 * Packed 32-bit structure
193 * +----------+----------+--------------+--------+
194 * | Reserved | QCMAP ID | interface id | STA ID |
195 * +----------+----------+--------------+--------+
196 */
197struct hdd_ipa_cld_hdr {
198 uint8_t reserved[2];
199 uint8_t iface_id;
200 uint8_t sta_id;
201} __packed;
202
203struct hdd_ipa_rx_hdr {
204 struct hdd_ipa_cld_hdr cld_hdr;
205 struct ethhdr eth;
206} __packed;
207
208struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700209 bool exception;
210 hdd_adapter_t *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211 struct hdd_ipa_iface_context *iface_context;
212 struct ipa_rx_data *ipa_tx_desc;
213};
214
215struct hdd_ipa_uc_rx_hdr {
216 struct ethhdr eth;
217} __packed;
218
219struct hdd_ipa_sys_pipe {
220 uint32_t conn_hdl;
221 uint8_t conn_hdl_valid;
222 struct ipa_sys_connect_params ipa_sys_params;
223};
224
225struct hdd_ipa_iface_stats {
226 uint64_t num_tx;
227 uint64_t num_tx_drop;
228 uint64_t num_tx_err;
229 uint64_t num_tx_cac_drop;
230 uint64_t num_rx_prefilter;
231 uint64_t num_rx_ipa_excep;
232 uint64_t num_rx_recv;
233 uint64_t num_rx_recv_mul;
234 uint64_t num_rx_send_desc_err;
235 uint64_t max_rx_mul;
236};
237
238struct hdd_ipa_priv;
239
240struct hdd_ipa_iface_context {
241 struct hdd_ipa_priv *hdd_ipa;
242 hdd_adapter_t *adapter;
243 void *tl_context;
244
245 enum ipa_client_type cons_client;
246 enum ipa_client_type prod_client;
247
248 uint8_t iface_id; /* This iface ID */
249 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530250 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800251 uint32_t ifa_address;
252 struct hdd_ipa_iface_stats stats;
253};
254
255struct hdd_ipa_stats {
256 uint32_t event[IPA_WLAN_EVENT_MAX];
257 uint64_t num_send_msg;
258 uint64_t num_free_msg;
259
260 uint64_t num_rm_grant;
261 uint64_t num_rm_release;
262 uint64_t num_rm_grant_imm;
263 uint64_t num_cons_perf_req;
264 uint64_t num_prod_perf_req;
265
266 uint64_t num_rx_drop;
267 uint64_t num_rx_ipa_tx_dp;
268 uint64_t num_rx_ipa_splice;
269 uint64_t num_rx_ipa_loop;
270 uint64_t num_rx_ipa_tx_dp_err;
271 uint64_t num_rx_ipa_write_done;
272 uint64_t num_max_ipa_tx_mul;
273 uint64_t num_rx_ipa_hw_maxed_out;
274 uint64_t max_pend_q_cnt;
275
276 uint64_t num_tx_comp_cnt;
277 uint64_t num_tx_queued;
278 uint64_t num_tx_dequeued;
279 uint64_t num_max_pm_queue;
280
281 uint64_t num_freeq_empty;
282 uint64_t num_pri_freeq_empty;
283 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800284 uint64_t num_tx_fwd_ok;
285 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800286};
287
288struct ipa_uc_stas_map {
289 bool is_reserved;
290 uint8_t sta_id;
291};
292struct op_msg_type {
293 uint8_t msg_t;
294 uint8_t rsvd;
295 uint16_t op_code;
296 uint16_t len;
297 uint16_t rsvd_snd;
298};
299
300struct ipa_uc_fw_stats {
301 uint32_t tx_comp_ring_base;
302 uint32_t tx_comp_ring_size;
303 uint32_t tx_comp_ring_dbell_addr;
304 uint32_t tx_comp_ring_dbell_ind_val;
305 uint32_t tx_comp_ring_dbell_cached_val;
306 uint32_t tx_pkts_enqueued;
307 uint32_t tx_pkts_completed;
308 uint32_t tx_is_suspend;
309 uint32_t tx_reserved;
310 uint32_t rx_ind_ring_base;
311 uint32_t rx_ind_ring_size;
312 uint32_t rx_ind_ring_dbell_addr;
313 uint32_t rx_ind_ring_dbell_ind_val;
314 uint32_t rx_ind_ring_dbell_ind_cached_val;
315 uint32_t rx_ind_ring_rdidx_addr;
316 uint32_t rx_ind_ring_rd_idx_cached_val;
317 uint32_t rx_refill_idx;
318 uint32_t rx_num_pkts_indicated;
319 uint32_t rx_buf_refilled;
320 uint32_t rx_num_ind_drop_no_space;
321 uint32_t rx_num_ind_drop_no_buf;
322 uint32_t rx_is_suspend;
323 uint32_t rx_reserved;
324};
325
326struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530327 qdf_list_node_t node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800328 hdd_adapter_t *adapter;
329 enum ipa_wlan_event type;
330 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530331 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800332};
333
334/**
335 * struct uc_rm_work_struct
336 * @work: uC RM work
337 * @event: IPA RM event
338 */
339struct uc_rm_work_struct {
340 struct work_struct work;
341 enum ipa_rm_event event;
342};
343
344/**
345 * struct uc_op_work_struct
346 * @work: uC OP work
347 * @msg: OP message
348 */
349struct uc_op_work_struct {
350 struct work_struct work;
351 struct op_msg_type *msg;
352};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800353
354/**
355 * struct uc_rt_debug_info
356 * @time: system time
357 * @ipa_excep_count: IPA exception packet count
358 * @rx_drop_count: IPA Rx drop packet count
359 * @net_sent_count: IPA Rx packet sent to network stack count
360 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800361 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800362 * @tx_fwd_count: IPA Tx forward packet count
363 * @rx_destructor_call: IPA Rx packet destructor count
364 */
365struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530366 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800367 uint64_t ipa_excep_count;
368 uint64_t rx_drop_count;
369 uint64_t net_sent_count;
370 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800371 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800372 uint64_t tx_fwd_count;
373 uint64_t rx_destructor_call;
374};
375
376struct hdd_ipa_priv {
377 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
378 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
379 uint8_t num_iface;
380 enum hdd_ipa_rm_state rm_state;
381 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530382 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800383 * APIs as it is taken care gracefully. Without this, kernel would throw
384 * an warning if spin_lock_bh is used while IRQ is disabled
385 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530386 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800387 struct uc_rm_work_struct uc_rm_work;
388 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530389 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800390 struct delayed_work wake_lock_work;
391 bool wake_lock_released;
392
393 enum ipa_client_type prod_client;
394
395 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530396 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800397 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530398 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800399 bool suspended;
400
401 uint32_t pending_hw_desc_cnt;
402 uint32_t hw_desc_cnt;
403 spinlock_t q_lock;
404 uint32_t freeq_cnt;
405 struct list_head free_desc_head;
406
407 uint32_t pend_q_cnt;
408 struct list_head pend_desc_head;
409
410 hdd_context_t *hdd_ctx;
411
412 struct dentry *debugfs_dir;
413 struct hdd_ipa_stats stats;
414
415 struct notifier_block ipv4_notifier;
416 uint32_t curr_prod_bw;
417 uint32_t curr_cons_bw;
418
419 uint8_t activated_fw_pipe;
420 uint8_t sap_num_connected_sta;
421 uint8_t sta_connected;
422 uint32_t tx_pipe_handle;
423 uint32_t rx_pipe_handle;
424 bool resource_loading;
425 bool resource_unloading;
426 bool pending_cons_req;
427 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530428 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530429 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700430 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431 uint32_t ipa_tx_packets_diff;
432 uint32_t ipa_rx_packets_diff;
433 uint32_t ipa_p_tx_packets;
434 uint32_t ipa_p_rx_packets;
435 uint32_t stat_req_reason;
436 uint64_t ipa_tx_forward;
437 uint64_t ipa_rx_discard;
438 uint64_t ipa_rx_net_send_count;
439 uint64_t ipa_rx_internel_drop_count;
440 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530441 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800442 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
443 unsigned int rt_buf_fill_index;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800444 struct ipa_wdi_in_params cons_pipe_in;
445 struct ipa_wdi_in_params prod_pipe_in;
446 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800447 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530448 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530449 qdf_mutex_t rt_debug_lock;
450 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800451 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800452 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530453 qdf_dma_addr_t tx_comp_doorbell_paddr;
454 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800455
456 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
457 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800458};
459
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800460/**
Houston Hoffman23e76f92016-02-26 12:19:11 -0800461 * FIXME: The following conversion routines are just stubs.
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800462 * They will be implemented fully by another update.
463 * The stubs will let the compile go ahead, and functionality
464 * is broken.
465 * This should be OK and IPA is not enabled yet
466 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700467static void *wlan_hdd_stub_priv_to_addr(uint32_t priv)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800468{
469 void *vaddr;
470 uint32_t ipa_priv = priv;
471
472 vaddr = &ipa_priv; /* just to use the var */
473 vaddr = NULL;
474 return vaddr;
475}
476
Jeff Johnsond7720632016-10-05 16:04:32 -0700477static uint32_t wlan_hdd_stub_addr_to_priv(void *ptr)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800478{
479 uint32_t ipa_priv = 0;
480
481 BUG_ON(ptr == NULL);
482 return ipa_priv;
483}
Leo Changcc923e22016-06-16 15:29:03 -0700484
485#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
486#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800487#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
488#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
489#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
490#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
491#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
492#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700493#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
494 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800495
496#define HDD_IPA_GET_IFACE_ID(_data) \
497 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
498
499#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530500 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501 "%s:%d: "fmt, __func__, __LINE__, ## args)
502
Govind Singhb6a89772016-08-12 11:23:35 +0530503#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
504 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
505 "%s:%d: "fmt, __func__, __LINE__, ## args)
506
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
508 do { \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530509 QDF_TRACE(QDF_MODULE_ID_HDD, _lvl, "%s:", _prefix); \
510 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800511 } while (0)
512
513#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
514 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
515
516#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
517 do { \
518 hdd_ipa->ipa_rx_internel_drop_count++; \
519 } while (0)
520#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
521 do { \
522 hdd_ipa->ipa_rx_net_send_count++; \
523 } while (0)
524#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
525
Leo Chang07b28f62016-05-11 12:29:22 -0700526#if defined (QCA_WIFI_3_0) && defined (CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800527#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
528do { \
529 pipe_in.u.ul.rdy_ring_rp_va = \
530 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
531 pipe_in.u.ul.rdy_comp_ring_base_pa = \
532 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
533 pipe_in.u.ul.rdy_comp_ring_size = \
534 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
535 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
536 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
537 pipe_in.u.ul.rdy_comp_ring_wp_va = \
538 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800539} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700540
541#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800542#else
543/* Do nothing */
544#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
Leo Chang63d73612016-10-18 18:09:43 -0700545#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700546#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800547
Yun Parkb187d542016-11-14 18:10:04 -0800548#define HDD_IPA_DBG_DUMP_RX_LEN 32
549#define HDD_IPA_DBG_DUMP_TX_LEN 48
550
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800551static struct hdd_ipa_adapter_2_client {
552 enum ipa_client_type cons_client;
553 enum ipa_client_type prod_client;
554} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
555 {
556 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
557 }, {
558 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
559 }, {
560 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
561 },
562};
563
564/* For Tx pipes, use Ethernet-II Header format */
565struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
566 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800567 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800568 0x00000000,
569 0x00000000
570 },
571 {
572 0x00000000
573 },
574 {
575 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
576 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
577 0x0008
578 }
579};
580
581/* For Tx pipes, use 802.3 Header format */
582static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
583 {
584 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
585 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
586 0x00 /* length can be zero */
587 },
588 {
589 /* LLC SNAP header 8 bytes */
590 0xaa, 0xaa,
591 {0x03, 0x00, 0x00, 0x00},
592 0x0008 /* type value(2 bytes) ,filled by wlan */
593 /* 0x0800 - IPV4, 0x86dd - IPV6 */
594 }
595};
596
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800597static struct hdd_ipa_priv *ghdd_ipa;
598
599/* Local Function Prototypes */
600static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
601 unsigned long data);
602static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
603 unsigned long data);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800604static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800605
606static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Mohit Khannafa99aea2016-05-12 21:43:13 -0700607static void hdd_ipa_uc_proc_pending_event (struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800608
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800609#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
610 defined(IPA_CLIENT_IS_MHI_CONS))
611/**
612 * hdd_ipa_uc_get_db_paddr() - Get Doorbell physical address
613 * @db_paddr: Doorbell physical address should be given bu IPA
614 * @client: IPA client type
615 *
616 * Query doorbell physical address from IPA
617 * IPA will give physical address for TX COMP and RX READY
618 *
619 * Return: None
620 */
621static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
622 enum ipa_client_type client)
623{
624 struct ipa_wdi_db_params dbpa;
625
626 dbpa.client = client;
627 ipa_uc_wdi_get_dbpa(&dbpa);
628 *db_paddr = dbpa.uc_door_bell_pa;
629 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s PROD DB get dbpa 0x%x",
630 __func__, (unsigned int)dbpa.uc_door_bell_pa);
631}
632
633/**
634 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
635 * @priv_ctxt: hdd ipa local context
636 *
637 * Will be called by IPA context.
638 * It's atomic context, then should be scheduled to kworker thread
639 *
640 * Return: None
641 */
642static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
643{
644 struct hdd_ipa_priv *hdd_ipa;
645 struct op_msg_type *msg;
646 struct uc_op_work_struct *uc_op_work;
647
648 if (priv_ctxt == NULL) {
649 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
650 return;
651 }
652
653 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
654 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
655 if (!msg) {
656 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
657 return;
658 }
659
660 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
661
662 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
663
664 /* When the same uC OPCODE is already pended, just return */
665 if (uc_op_work->msg)
666 return;
667
668 uc_op_work->msg = msg;
669 schedule_work(&uc_op_work->work);
670}
671
672/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800673 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
674 * @ctrl: WDI control value
675 *
676 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
677 *
678 * Return: 0 on message send to ipa, -1 on failure
679 */
680static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
681{
682 struct ipa_msg_meta meta;
683 struct ipa_wlan_msg *ipa_msg;
684 int ret = 0;
685
686 /* WDI enable message to IPA */
687 meta.msg_len = sizeof(*ipa_msg);
688 ipa_msg = qdf_mem_malloc(meta.msg_len);
689 if (ipa_msg == NULL) {
690 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
691 "msg allocation failed");
692 return -ENOMEM;
693 }
694
695 if (ctrl == true)
696 meta.msg_type = WLAN_WDI_ENABLE;
697 else
698 meta.msg_type = WLAN_WDI_DISABLE;
699
700 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
701 "ipa_send_msg(Evt:%d)", meta.msg_type);
702 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
703 if (ret) {
704 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
705 "ipa_send_msg(Evt:%d)-fail=%d",
706 meta.msg_type, ret);
707 qdf_mem_free(ipa_msg);
708 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800709 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800710}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800711
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800712/**
713 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
714 * @hdd_ipa: HDD IPA local context
715 *
716 * Register IPA UC ready callback function to IPA kernel driver
717 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
718 * open WDI pipe after WLAN driver loading finished
719 *
720 * Return: 0 Success
721 * -EPERM Registration fail
722 */
723static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
724{
725 struct ipa_wdi_uc_ready_params uc_ready_param;
726 int ret = 0;
727
728 hdd_ipa->uc_loaded = false;
729 uc_ready_param.priv = (void *)hdd_ipa;
730 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
731 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
732 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
733 "UC Ready CB register fail");
734 return -EPERM;
735 }
736 if (true == uc_ready_param.is_uC_ready) {
737 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "UC Ready");
738 hdd_ipa->uc_loaded = true;
739 } else {
740 ret = hdd_ipa_uc_send_wdi_control_msg(false);
741 }
742
743 return ret;
744}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800745#else
746static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
747 enum ipa_client_type client)
748{
749 /* Do nothing */
750}
751
752static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
753{
754 hdd_ipa->uc_loaded = true;
755 return 0;
756}
757
758static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
759{
760 return 0;
761}
762#endif
763
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800764/**
765 * hdd_ipa_is_enabled() - Is IPA enabled?
766 * @hdd_ctx: Global HDD context
767 *
768 * Return: true if IPA is enabled, false otherwise
769 */
770bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
771{
772 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
773}
774
775/**
776 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
777 * @hdd_ctx: Global HDD context
778 *
779 * Return: true if IPA uC offload is enabled, false otherwise
780 */
781bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
782{
783 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
784}
785
786/**
787 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
788 * @hdd_ctx: Global HDD context
789 *
790 * Return: true if STA mode IPA uC offload is enabled, false otherwise
791 */
792static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
793{
794 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
795}
796
797/**
Guolei Bianca144d82016-11-10 11:07:42 +0800798 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
799 * @hdd_ipa: Global HDD IPA context
800 *
801 * Return: None
802 */
803#ifdef IPA_UC_STA_OFFLOAD
804static inline void hdd_ipa_uc_sta_reset_sta_connected(
805 struct hdd_ipa_priv *hdd_ipa)
806{
807 vos_lock_acquire(&hdd_ipa->event_lock);
808 hdd_ipa->sta_connected = 0;
809 vos_lock_release(&hdd_ipa->event_lock);
810}
811#else
812static inline void hdd_ipa_uc_sta_reset_sta_connected(
813 struct hdd_ipa_priv *hdd_ipa)
814{
815}
816#endif
817
818/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800819 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
820 * @hdd_ipa: Global HDD IPA context
821 *
822 * Return: true if pre-filter is enabled, otherwise false
823 */
824static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
825{
826 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
827 HDD_IPA_PRE_FILTER_ENABLE_MASK);
828}
829
830/**
831 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
832 * @hdd_ipa: Global HDD IPA context
833 *
834 * Return: true if IPv6 is enabled, otherwise false
835 */
836static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
837{
838 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
839}
840
841/**
842 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
843 * @hdd_ipa: Global HDD IPA context
844 *
845 * Return: true if resource manager is enabled, otherwise false
846 */
847static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
848{
849 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
850}
851
852/**
853 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
854 * @hdd_ipa: Global HDD IPA context
855 *
856 * Return: true if resource manager is enabled, otherwise false
857 */
858static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
859{
860 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
861}
862
863/**
864 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
865 * @hdd_ipa: Global HDD IPA context
866 *
867 * Return: true if clock scaling is enabled, otherwise false
868 */
869static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
870{
871 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
872 HDD_IPA_CLK_SCALING_ENABLE_MASK |
873 HDD_IPA_RM_ENABLE_MASK);
874}
875
876/**
877 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
878 * @ctext: pointer to hdd context.
879 *
880 * If rt debug enabled, periodically called, and fill debug buffer
881 *
882 * Return: none
883 */
884static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
885{
886 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
887 struct hdd_ipa_priv *hdd_ipa;
888 struct uc_rt_debug_info *dump_info = NULL;
889
890 if (wlan_hdd_validate_context(hdd_ctx))
891 return;
892
893 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530894 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800895 "%s: IPA UC is not enabled", __func__);
896 return;
897 }
898
899 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
900
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530901 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800902 dump_info = &hdd_ipa->rt_bug_buffer[
903 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
904
Deepthi Gowri6acee342016-10-28 15:00:38 +0530905 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800906 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
907 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
908 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800909 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800910 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
911 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800912 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
913 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530914 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800915
Anurag Chouhan210db072016-02-22 18:42:15 +0530916 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
918}
919
920/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700921 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800922 * @hdd_ctx: pointer to hdd context.
923 *
924 * If rt debug enabled, dump debug buffer contents based on requirement
925 *
926 * Return: none
927 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700928static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929{
930 struct hdd_ipa_priv *hdd_ipa;
931 unsigned int dump_count;
932 unsigned int dump_index;
933 struct uc_rt_debug_info *dump_info = NULL;
934
935 if (wlan_hdd_validate_context(hdd_ctx))
936 return;
937
938 hdd_ipa = hdd_ctx->hdd_ipa;
939 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530940 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941 "%s: IPA UC is not enabled", __func__);
942 return;
943 }
944
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530945 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800946 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530947 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800948 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530950 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951 for (dump_count = 0;
952 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
953 dump_count++) {
954 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
955 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
956 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530957 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530958 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800959 dump_info->time, dump_info->ipa_excep_count,
960 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800961 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962 dump_info->rx_destructor_call,
963 dump_info->rx_discard_count);
964 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530965 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530966 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800967 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
968}
969
970/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700971 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
972 * __hdd_ipa_uc_rt_debug_host_dump
973 * @hdd_ctx: pointer to hdd context.
974 *
975 * If rt debug enabled, dump debug buffer contents based on requirement
976 *
977 * Return: none
978 */
979void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
980{
981 cds_ssr_protect(__func__);
982 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
983 cds_ssr_unprotect(__func__);
984}
985
986/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800987 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
988 * @ctext: pointer to hdd context.
989 *
990 * periodically called by timer expire
991 * will try to alloc dummy memory and detect out of memory condition
992 * if out of memory detected, dump wlan-ipa stats
993 *
994 * Return: none
995 */
996static void hdd_ipa_uc_rt_debug_handler(void *ctext)
997{
998 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700999 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001000 void *dummy_ptr = NULL;
1001
1002 if (wlan_hdd_validate_context(hdd_ctx))
1003 return;
1004
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001005 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1006
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001007 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08001008 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001009 return;
1010 }
1011
1012 /* Allocate dummy buffer periodically and free immediately. this will
1013 * proactively detect OOM and if allocation fails dump ipa stats
1014 */
1015 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
1016 GFP_KERNEL | GFP_ATOMIC);
1017 if (!dummy_ptr) {
Yun Parkb187d542016-11-14 18:10:04 -08001018 hdd_alert("Dummy alloc fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1020 hdd_ipa_uc_stat_request(
Krunal Sonibe766b02016-03-10 13:00:44 -08001021 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001022 } else {
1023 kfree(dummy_ptr);
1024 }
1025
Anurag Chouhan210db072016-02-22 18:42:15 +05301026 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 HDD_IPA_UC_RT_DEBUG_PERIOD);
1028}
1029
1030/**
Yun Parkb187d542016-11-14 18:10:04 -08001031 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032 * @skb: packet pinter
1033 *
1034 * when free data packet, will be invoked by wlan client and will increase
1035 * free counter
1036 *
1037 * Return: none
1038 */
Jeff Johnsond7720632016-10-05 16:04:32 -07001039static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001040{
1041 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301042 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043 "%s: invalid hdd context", __func__);
1044 return;
1045 }
1046
1047 ghdd_ipa->ipa_rx_destructor_count++;
1048}
1049
1050/**
Yun Parkb187d542016-11-14 18:10:04 -08001051 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052 * @hdd_ctx: hdd main context
1053 *
1054 * free all rt debugging resources
1055 *
1056 * Return: none
1057 */
1058static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
1059{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001060 struct hdd_ipa_priv *hdd_ipa;
1061
1062 if (wlan_hdd_validate_context(hdd_ctx))
1063 return;
1064
1065 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001066
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301067 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001068
1069 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08001070 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001071 return;
1072 }
1073
Anurag Chouhan210db072016-02-22 18:42:15 +05301074 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001075 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1076 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1077 }
1078 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1079
1080 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301081 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1082 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001083 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301084 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001085}
1086
1087/**
Yun Parkb187d542016-11-14 18:10:04 -08001088 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001089 * @hdd_ctx: hdd main context
1090 *
1091 * alloc and initialize all rt debugging resources
1092 *
1093 * Return: none
1094 */
1095static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
1096{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001097 struct hdd_ipa_priv *hdd_ipa;
1098
1099 if (wlan_hdd_validate_context(hdd_ctx))
1100 return;
1101
1102 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301104 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301106 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107 sizeof(struct uc_rt_debug_info) *
1108 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1109 hdd_ipa->ipa_tx_forward = 0;
1110 hdd_ipa->ipa_rx_discard = 0;
1111 hdd_ipa->ipa_rx_net_send_count = 0;
1112 hdd_ipa->ipa_rx_internel_drop_count = 0;
1113 hdd_ipa->ipa_rx_destructor_count = 0;
1114
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001115 /* Reatime debug enable on feature enable */
1116 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08001117 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118 return;
1119 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001120
1121 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1122 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1123 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1124 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1125
Anurag Chouhan210db072016-02-22 18:42:15 +05301126 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001127 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301128 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001129 HDD_IPA_UC_RT_DEBUG_PERIOD);
1130
1131}
1132
1133/**
Yun Parkb187d542016-11-14 18:10:04 -08001134 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1135 * @hdd_ipa: HDD IPA struct
1136 *
1137 * Dump entries in struct hdd_ipa
1138 *
1139 * Return: none
1140 */
1141static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1142{
1143 int i;
1144
1145 /* HDD IPA */
1146 hdd_err("==== HDD IPA ====\n"
1147 "num_iface: %d\n"
1148 "rm_state: %d\n"
1149 "rm_lock: %p\n"
1150 "uc_rm_work: %p\n"
1151 "uc_op_work: %p\n"
1152 "wake_lock: %p\n"
1153 "wake_lock_work: %p\n"
1154 "wake_lock_released: %d\n"
1155 "prod_client: %d\n"
1156 "tx_ref_cnt: %d\n"
1157 "pm_queue_head----\n"
1158 "\thead: %p\n"
1159 "\ttail: %p\n"
1160 "\tqlen: %d\n"
1161 "pm_work: %p\n"
1162 "pm_lock: %p\n"
1163 "suspended: %d\n",
1164 hdd_ipa->num_iface,
1165 hdd_ipa->rm_state,
1166 &hdd_ipa->rm_lock,
1167 &hdd_ipa->uc_rm_work,
1168 &hdd_ipa->uc_op_work,
1169 &hdd_ipa->wake_lock,
1170 &hdd_ipa->wake_lock_work,
1171 hdd_ipa->wake_lock_released,
1172 hdd_ipa->prod_client,
1173 hdd_ipa->tx_ref_cnt.counter,
1174 hdd_ipa->pm_queue_head.head,
1175 hdd_ipa->pm_queue_head.tail,
1176 hdd_ipa->pm_queue_head.qlen,
1177 &hdd_ipa->pm_work,
1178 &hdd_ipa->pm_lock,
1179 hdd_ipa->suspended);
1180 hdd_err("\npending_hw_desc_cnt: %d\n"
1181 "hw_desc_cnt: %d\n"
1182 "q_lock: %p\n"
1183 "freeq_cnt: %d\n"
1184 "free_desc_head----\n"
1185 "\tnext: %p\n"
1186 "\tprev: %p\n"
1187 "pend_q_cnt: %d\n"
1188 "pend_desc_head----\n"
1189 "\tnext: %p\n"
1190 "\tprev: %p\n"
1191 "hdd_ctx: %p\n"
1192 "debugfs_dir: %p\n"
1193 "stats: %p\n"
1194 "ipv4_notifier: %p\n"
1195 "curr_prod_bw: %d\n"
1196 "curr_cons_bw: %d\n"
1197 "activated_fw_pipe: %d\n"
1198 "sap_num_connected_sta: %d\n"
1199 "sta_connected: %d\n",
1200 hdd_ipa->pending_hw_desc_cnt,
1201 hdd_ipa->hw_desc_cnt,
1202 &hdd_ipa->q_lock,
1203 hdd_ipa->freeq_cnt,
1204 hdd_ipa->free_desc_head.next,
1205 hdd_ipa->free_desc_head.prev,
1206 hdd_ipa->pend_q_cnt,
1207 hdd_ipa->pend_desc_head.next,
1208 hdd_ipa->pend_desc_head.prev,
1209 hdd_ipa->hdd_ctx,
1210 hdd_ipa->debugfs_dir,
1211 &hdd_ipa->stats,
1212 &hdd_ipa->ipv4_notifier,
1213 hdd_ipa->curr_prod_bw,
1214 hdd_ipa->curr_cons_bw,
1215 hdd_ipa->activated_fw_pipe,
1216 hdd_ipa->sap_num_connected_sta,
1217 (unsigned int)hdd_ipa->sta_connected
1218 );
1219 hdd_err("\ntx_pipe_handle: 0x%x\n"
1220 "rx_pipe_handle: 0x%x\n"
1221 "resource_loading: %d\n"
1222 "resource_unloading: %d\n"
1223 "pending_cons_req: %d\n"
1224 "pending_event----\n"
1225 "\tanchor.next: %p\n"
1226 "\tanchor.prev: %p\n"
1227 "\tcount: %d\n"
1228 "\tmax_size: %d\n"
1229 "event_lock: %p\n"
1230 "ipa_tx_packets_diff: %d\n"
1231 "ipa_rx_packets_diff: %d\n"
1232 "ipa_p_tx_packets: %d\n"
1233 "ipa_p_rx_packets: %d\n"
1234 "stat_req_reason: %d\n",
1235 hdd_ipa->tx_pipe_handle,
1236 hdd_ipa->rx_pipe_handle,
1237 hdd_ipa->resource_loading,
1238 hdd_ipa->resource_unloading,
1239 hdd_ipa->pending_cons_req,
1240 hdd_ipa->pending_event.anchor.next,
1241 hdd_ipa->pending_event.anchor.prev,
1242 hdd_ipa->pending_event.count,
1243 hdd_ipa->pending_event.max_size,
1244 &hdd_ipa->event_lock,
1245 hdd_ipa->ipa_tx_packets_diff,
1246 hdd_ipa->ipa_rx_packets_diff,
1247 hdd_ipa->ipa_p_tx_packets,
1248 hdd_ipa->ipa_p_rx_packets,
1249 hdd_ipa->stat_req_reason);
1250
1251 hdd_err("assoc_stas_map([id]is_reserved/sta_id): ");
1252 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
1253 hdd_err(" [%d]%d/%d", i,
1254 hdd_ipa->assoc_stas_map[i].is_reserved,
1255 hdd_ipa->assoc_stas_map[i].sta_id);
1256 }
1257}
1258
1259/**
1260 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1261 * @hdd_ipa: HDD IPA struct
1262 *
1263 * Dump entire struct hdd_ipa_sys_pipe
1264 *
1265 * Return: none
1266 */
1267static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1268{
1269 int i;
1270
1271 /* IPA SYS Pipes */
1272 hdd_err("==== IPA SYS Pipes ====\n");
1273
1274 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1275 struct hdd_ipa_sys_pipe *sys_pipe;
1276 struct ipa_sys_connect_params *ipa_sys_params;
1277
1278 sys_pipe = &hdd_ipa->sys_pipe[i];
1279 ipa_sys_params = &sys_pipe->ipa_sys_params;
1280
1281 hdd_err("sys_pipe[%d]----\n"
1282 "\tconn_hdl: 0x%x\n"
1283 "\tconn_hdl_valid: %d\n"
1284 "\tnat_en: %d\n"
1285 "\thdr_len %d\n"
1286 "\thdr_additional_const_len: %d\n"
1287 "\thdr_ofst_pkt_size_valid: %d\n"
1288 "\thdr_ofst_pkt_size: %d\n"
1289 "\thdr_little_endian: %d\n"
1290 "\tmode: %d\n"
1291 "\tclient: %d\n"
1292 "\tdesc_fifo_sz: %d\n"
1293 "\tpriv: %p\n"
1294 "\tnotify: %p\n"
1295 "\tskip_ep_cfg: %d\n"
1296 "\tkeep_ipa_awake: %d\n",
1297 i,
1298 sys_pipe->conn_hdl,
1299 sys_pipe->conn_hdl_valid,
1300 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1301 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1302 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1303 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1304 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1305 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1306 ipa_sys_params->ipa_ep_cfg.mode.mode,
1307 ipa_sys_params->client,
1308 ipa_sys_params->desc_fifo_sz,
1309 ipa_sys_params->priv,
1310 ipa_sys_params->notify,
1311 ipa_sys_params->skip_ep_cfg,
1312 ipa_sys_params->keep_ipa_awake);
1313 }
1314}
1315
1316/**
1317 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1318 * @hdd_ipa: HDD IPA struct
1319 *
1320 * Dump entire struct hdd_ipa_iface_context
1321 *
1322 * Return: none
1323 */
1324static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1325{
1326 int i;
1327
1328 /* IPA Interface Contexts */
1329 hdd_err("==== IPA Interface Contexts ====\n");
1330
1331 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1332 struct hdd_ipa_iface_context *iface_context;
1333
1334 iface_context = &hdd_ipa->iface_context[i];
1335
1336 hdd_err("iface_context[%d]----\n"
1337 "\thdd_ipa: %p\n"
1338 "\tadapter: %p\n"
1339 "\ttl_context: %p\n"
1340 "\tcons_client: %d\n"
1341 "\tprod_client: %d\n"
1342 "\tiface_id: %d\n"
1343 "\tsta_id: %d\n"
1344 "\tinterface_lock: %p\n"
1345 "\tifa_address: 0x%x\n",
1346 i,
1347 iface_context->hdd_ipa,
1348 iface_context->adapter,
1349 iface_context->tl_context,
1350 iface_context->cons_client,
1351 iface_context->prod_client,
1352 iface_context->iface_id,
1353 iface_context->sta_id,
1354 &iface_context->interface_lock,
1355 iface_context->ifa_address);
1356 }
1357}
1358
1359/**
1360 * hdd_ipa_dump_info() - dump HDD IPA struct
1361 * @pHddCtx: hdd main context
1362 *
1363 * Dump entire struct hdd_ipa
1364 *
1365 * Return: none
1366 */
1367void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1368{
1369 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1370
1371 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1372 hdd_ipa_dump_sys_pipe(hdd_ipa);
1373 hdd_ipa_dump_iface_context(hdd_ipa);
1374}
1375
1376/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001377 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001378 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001379 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1380 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001381 *
1382 * Return: true if IPA is enabled, false otherwise
1383 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001384static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001385 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1386{
1387 struct hdd_ipa_priv *hdd_ipa;
1388
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001389 *ipa_tx_diff = 0;
1390 *ipa_rx_diff = 0;
1391
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001392 if (wlan_hdd_validate_context(hdd_ctx))
1393 return;
1394
1395 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1396
1397 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1398 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001399 return;
1400 }
1401
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301402 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001403 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1404 (false == hdd_ipa->resource_loading)) {
1405 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1406 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001407 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001408 *ipa_tx_diff, *ipa_rx_diff);
1409 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301410 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411 return;
1412}
1413
1414/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001415 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1416 * @hdd_ctx: Global HDD context
1417 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1418 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1419 *
1420 * Return: true if IPA is enabled, false otherwise
1421 */
1422void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1423 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1424{
1425 cds_ssr_protect(__func__);
1426 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1427 cds_ssr_unprotect(__func__);
1428}
1429
1430/**
1431 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001432 * @adapter: network adapter
1433 * @reason: STAT REQ Reason
1434 *
1435 * Return: None
1436 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001437static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001439 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001440 struct hdd_ipa_priv *hdd_ipa;
1441
1442 if (!adapter) {
1443 return;
1444 }
1445
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001446 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1447
1448 if (wlan_hdd_validate_context(hdd_ctx))
1449 return;
1450
1451 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1452 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1453 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001454 return;
1455 }
1456
Yun Parkb187d542016-11-14 18:10:04 -08001457 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301458 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001459 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1460 (false == hdd_ipa->resource_loading)) {
1461 hdd_ipa->stat_req_reason = reason;
1462 wma_cli_set_command(
1463 (int)adapter->sessionId,
1464 (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
1465 0, VDEV_CMD);
1466 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301467 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468}
1469
1470/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001471 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1472 * @adapter: network adapter
1473 * @reason: STAT REQ Reason
1474 *
1475 * Return: None
1476 */
1477void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1478{
1479 cds_ssr_protect(__func__);
1480 __hdd_ipa_uc_stat_request(adapter, reason);
1481 cds_ssr_unprotect(__func__);
1482}
1483
1484/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001485 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1486 * @hdd_ipa: Global HDD IPA context
1487 * @sta_add: Should station be added
1488 * @sta_id: ID of the station being queried
1489 *
1490 * Return: true if the station was found
1491 */
1492static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1493 bool sta_add, uint8_t sta_id)
1494{
1495 bool sta_found = false;
1496 uint8_t idx;
1497 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1498 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1499 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1500 sta_found = true;
1501 break;
1502 }
1503 }
1504 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301505 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001506 "%s: STA ID %d already exist, cannot add",
1507 __func__, sta_id);
1508 return sta_found;
1509 }
1510 if (sta_add) {
1511 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1512 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1513 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1514 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1515 return sta_found;
1516 }
1517 }
1518 }
1519 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301520 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001521 "%s: STA ID %d does not exist, cannot delete",
1522 __func__, sta_id);
1523 return sta_found;
1524 }
1525 if (!sta_add) {
1526 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1527 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1528 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1529 hdd_ipa->assoc_stas_map[idx].is_reserved =
1530 false;
1531 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1532 return sta_found;
1533 }
1534 }
1535 }
1536 return sta_found;
1537}
1538
1539/**
1540 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1541 * @hdd_ipa: Global HDD IPA context
1542 *
1543 * Return: 0 on success, negative errno if error
1544 */
1545static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1546{
1547 int result;
1548 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001549 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001550
1551 /* ACTIVATE TX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301552 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001553 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1554 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1556 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301557 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001558 "%s: Enable TX PIPE fail, code %d",
1559 __func__, result);
1560 return result;
1561 }
1562 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1563 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301564 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001565 "%s: Resume TX PIPE fail, code %d",
1566 __func__, result);
1567 return result;
1568 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001569 cdp_ipa_set_active(soc,
1570 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1571 true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572
1573 /* ACTIVATE RX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301574 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001575 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1576 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001577 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1578 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301579 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580 "%s: Enable RX PIPE fail, code %d",
1581 __func__, result);
1582 return result;
1583 }
1584 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1585 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301586 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001587 "%s: Resume RX PIPE fail, code %d",
1588 __func__, result);
1589 return result;
1590 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001591 cdp_ipa_set_active(soc,
1592 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1593 true, false);
Leo Change3e49442015-10-26 20:07:13 -07001594 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001595 return 0;
1596}
1597
1598/**
1599 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1600 * @hdd_ipa: Global HDD IPA context
1601 *
1602 * Return: 0 on success, negative errno if error
1603 */
1604static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1605{
1606 int result;
1607
Leo Change3e49442015-10-26 20:07:13 -07001608 hdd_ipa->ipa_pipes_down = true;
1609
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301610 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
1612 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301613 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614 "%s: Suspend RX PIPE fail, code %d",
1615 __func__, result);
1616 return result;
1617 }
1618 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1619 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301620 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001621 "%s: Disable RX PIPE fail, code %d",
1622 __func__, result);
1623 return result;
1624 }
1625
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301626 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001627 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
1628 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301629 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001630 "%s: Suspend TX PIPE fail, code %d",
1631 __func__, result);
1632 return result;
1633 }
1634 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1635 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301636 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001637 "%s: Disable TX PIPE fail, code %d",
1638 __func__, result);
1639 return result;
1640 }
1641
1642 return 0;
1643}
1644
1645/**
1646 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1647 * @hdd_ipa: Global HDD IPA context
1648 *
1649 * Return: 0 on success, negative errno if error
1650 */
1651static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1652{
1653 hdd_ipa->activated_fw_pipe = 0;
1654 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001655
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001656 /* If RM feature enabled
1657 * Request PROD Resource first
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08001658 * PROD resource may return sync or async manners
1659 */
Yun Park4cab6ee2015-10-27 11:43:40 -07001660 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
1661 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1662 /* RM PROD request sync return
1663 * enable pipe immediately
1664 */
1665 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301666 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001667 "%s: IPA WDI Pipe activation failed",
1668 __func__);
1669 hdd_ipa->resource_loading = false;
1670 return -EBUSY;
1671 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672 }
1673 } else {
1674 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001675 * Just enabled all the PIPEs
1676 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001677 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301678 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001679 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001680 __func__);
1681 hdd_ipa->resource_loading = false;
1682 return -EBUSY;
1683 }
1684 hdd_ipa->resource_loading = false;
1685 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001686
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301687 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001688 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 return 0;
1690}
1691
1692/**
1693 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1694 * @hdd_ipa: Global HDD IPA context
1695 *
1696 * Return: None
1697 */
1698static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1699{
1700 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001701 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
Yun Park7c4f31b2016-11-30 10:09:21 -08001703 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
1704 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
1705 QDF_ASSERT(0);
1706 return;
1707 }
1708
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709 hdd_ipa->resource_unloading = true;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301710 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW RX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001711 cdp_ipa_set_active(soc,
1712 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1713 false, false);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301714 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW TX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001715 cdp_ipa_set_active(soc,
1716 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1717 false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718}
1719
1720/**
1721 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
1722 * @context: User context registered with TL (the IPA Global context is
1723 * registered
1724 * @rxpkt: Packet containing the notification
1725 * @staid: ID of the station associated with the packet
1726 *
1727 * Return: None
1728 */
1729static void
1730hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
1731{
1732 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301733 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734
1735 /*
1736 * When SSR is going on or driver is unloading, just return.
1737 */
1738 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301739 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001741
1742 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1743 return;
1744
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301745 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001746 __func__, event);
1747
1748 switch (event) {
1749 case IPA_RM_RESOURCE_GRANTED:
1750 /* Differed RM Granted */
1751 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301752 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753 if ((false == hdd_ipa->resource_unloading) &&
1754 (!hdd_ipa->activated_fw_pipe)) {
1755 hdd_ipa_uc_enable_pipes(hdd_ipa);
1756 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301757 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758 break;
1759
1760 case IPA_RM_RESOURCE_RELEASED:
1761 /* Differed RM Released */
1762 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763 break;
1764
1765 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301766 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767 "%s, invalid event code %d", __func__, event);
1768 break;
1769 }
1770}
1771
1772/**
1773 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
1774 * @hdd_ipa: Global HDD IPA context
1775 * @event: IPA resource manager event to be deferred
1776 *
1777 * This function is called when a resource manager event is received
1778 * from firmware in interrupt context. This function will defer the
1779 * handling to the OL RX thread
1780 *
1781 * Return: None
1782 */
1783static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
1784{
1785 enum ipa_rm_event event;
1786 struct uc_rm_work_struct *uc_rm_work = container_of(work,
1787 struct uc_rm_work_struct, work);
1788 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
1789 struct hdd_ipa_priv, uc_rm_work);
1790
1791 cds_ssr_protect(__func__);
1792 event = uc_rm_work->event;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301793 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794 "%s, posted event %d", __func__, event);
1795
1796 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
1797 cds_ssr_unprotect(__func__);
1798
1799 return;
1800}
1801
1802/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08001803 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
1804 * @ipa_ctxt: hdd ipa local context
1805 *
1806 * Will handle IPA UC image loaded indication comes from IPA kernel
1807 *
1808 * Return: None
1809 */
1810static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt)
1811{
1812 struct ipa_wdi_out_params pipe_out;
1813
1814 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
1815 if (true == ipa_ctxt->uc_loaded) {
1816 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s : UC already loaded",
1817 __func__);
1818 return;
1819 }
1820
1821 ipa_ctxt->uc_loaded = true;
1822 /* Connect pipe */
1823 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
1824 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
1825 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
1826 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1827 "%s : TX PIPE Handle %d, DBPA 0x%llx",
1828 __func__, ipa_ctxt->tx_pipe_handle,
1829 (unsigned long long) pipe_out.uc_door_bell_pa);
1830
1831 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
1832 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
1833 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
1834 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1835 "%s : RX PIPE Handle %d, DBPA 0x%llx",
1836 __func__, ipa_ctxt->rx_pipe_handle,
1837 (unsigned long long) pipe_out.uc_door_bell_pa);
1838
1839 /* If already any STA connected, enable IPA/FW PIPEs */
1840 if (ipa_ctxt->sap_num_connected_sta) {
1841 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
1842 "Client already connected, enable IPA/FW PIPEs");
1843 hdd_ipa_uc_handle_first_con(ipa_ctxt);
1844 }
1845}
1846
1847/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848 * hdd_ipa_uc_op_cb() - IPA uC operation callback
1849 * @op_msg: operation message received from firmware
1850 * @usr_ctxt: user context registered with TL (we register the HDD Global
1851 * context)
1852 *
1853 * Return: None
1854 */
1855static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
1856{
1857 struct op_msg_type *msg = op_msg;
1858 struct ipa_uc_fw_stats *uc_fw_stat;
1859 struct IpaHwStatsWDIInfoData_t ipa_stat;
1860 struct hdd_ipa_priv *hdd_ipa;
1861 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301862 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001863
1864 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301865 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001866 return;
1867 }
1868
1869 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301870 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871 "%s, INVALID OPCODE %d", __func__, msg->op_code);
1872 return;
1873 }
1874
1875 hdd_ctx = (hdd_context_t *) usr_ctxt;
1876
1877 /*
1878 * When SSR is going on or driver is unloading, just return.
1879 */
1880 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301881 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301882 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001883 return;
1884 }
1885
1886 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1887
Govind Singhb6a89772016-08-12 11:23:35 +05301888 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08001889 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001890
1891 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
1892 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301893 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001894 hdd_ipa->activated_fw_pipe++;
1895 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
1896 hdd_ipa->resource_loading = false;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08001897 if (hdd_ipa->wdi_enabled == false) {
1898 hdd_ipa->wdi_enabled = true;
1899 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
1900 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
1901 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08001902 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08001904 if (hdd_ipa->pending_cons_req)
1905 ipa_rm_notify_completion(
1906 IPA_RM_RESOURCE_GRANTED,
1907 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08001908 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001909 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301910 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001911 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001912 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301913 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001914 hdd_ipa->activated_fw_pipe--;
1915 if (!hdd_ipa->activated_fw_pipe) {
1916 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08001917 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1918 ipa_rm_release_resource(
1919 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08001920 /*
1921 * Sync return success from IPA
1922 * Enable/resume all the PIPEs
1923 */
Yun Park5b635012015-12-02 15:05:01 -08001924 hdd_ipa->resource_unloading = false;
1925 hdd_ipa_uc_proc_pending_event(hdd_ipa);
1926 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301928 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001929 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001930 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001931 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001932 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301933 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001934 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001935 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936 "CE RING SIZE: %d\n"
1937 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001938 (unsigned long long)res->ce_sr_base_paddr,
1939 res->ce_sr_ring_size,
1940 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301941 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001942 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001943 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001944 "COMP RING SIZE: %d\n"
1945 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001946 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001947 (unsigned long long)res->tx_comp_ring_base_paddr,
1948 res->tx_comp_ring_size,
1949 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001950 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301951 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001952 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001953 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001955 "IND RING DBELL : 0x%llx\n"
1956 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001957 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08001958 "NUM TX FWD OK : %llu\n"
1959 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08001960 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001961 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08001962 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
1963 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001964 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08001965 hdd_ipa->stats.num_tx_fwd_ok,
1966 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301967 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001968 "==== IPA_UC WLAN_HOST CONTROL ====\n"
1969 "SAP NUM STAs: %d\n"
1970 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001971 "CONCURRENT MODE: %s\n"
1972 "TX PIPE HDL: 0x%x\n"
1973 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 "RSC LOADING : %d\n"
1975 "RSC UNLOADING : %d\n"
1976 "PNDNG CNS RQT : %d",
1977 hdd_ipa->sap_num_connected_sta,
1978 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08001979 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001980 hdd_ipa->tx_pipe_handle,
1981 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08001982 hdd_ipa->resource_loading,
1983 hdd_ipa->resource_unloading,
1984 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985
1986 /* STATs from FW */
1987 uc_fw_stat = (struct ipa_uc_fw_stats *)
1988 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301989 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001990 "==== IPA_UC WLAN_FW TX ====\n"
1991 "COMP RING BASE: 0x%x\n"
1992 "COMP RING SIZE: %d\n"
1993 "COMP RING DBELL : 0x%x\n"
1994 "COMP RING DBELL IND VAL : %d\n"
1995 "COMP RING DBELL CACHED VAL : %d\n"
1996 "COMP RING DBELL CACHED VAL : %d\n"
1997 "PKTS ENQ : %d\n"
1998 "PKTS COMP : %d\n"
1999 "IS SUSPEND : %d\n"
2000 "RSVD : 0x%x",
2001 uc_fw_stat->tx_comp_ring_base,
2002 uc_fw_stat->tx_comp_ring_size,
2003 uc_fw_stat->tx_comp_ring_dbell_addr,
2004 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2005 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2006 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2007 uc_fw_stat->tx_pkts_enqueued,
2008 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002009 uc_fw_stat->tx_is_suspend,
2010 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302011 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012 "==== IPA_UC WLAN_FW RX ====\n"
2013 "IND RING BASE: 0x%x\n"
2014 "IND RING SIZE: %d\n"
2015 "IND RING DBELL : 0x%x\n"
2016 "IND RING DBELL IND VAL : %d\n"
2017 "IND RING DBELL CACHED VAL : %d\n"
2018 "RDY IND ADDR : 0x%x\n"
2019 "RDY IND CACHE VAL : %d\n"
2020 "RFIL IND : %d\n"
2021 "NUM PKT INDICAT : %d\n"
2022 "BUF REFIL : %d\n"
2023 "NUM DROP NO SPC : %d\n"
2024 "NUM DROP NO BUF : %d\n"
2025 "IS SUSPND : %d\n"
2026 "RSVD : 0x%x\n",
2027 uc_fw_stat->rx_ind_ring_base,
2028 uc_fw_stat->rx_ind_ring_size,
2029 uc_fw_stat->rx_ind_ring_dbell_addr,
2030 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2031 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2032 uc_fw_stat->rx_ind_ring_rdidx_addr,
2033 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2034 uc_fw_stat->rx_refill_idx,
2035 uc_fw_stat->rx_num_pkts_indicated,
2036 uc_fw_stat->rx_buf_refilled,
2037 uc_fw_stat->rx_num_ind_drop_no_space,
2038 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002039 uc_fw_stat->rx_is_suspend,
2040 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002041 /* STATs from IPA */
2042 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302043 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002044 "==== IPA_UC IPA TX ====\n"
2045 "NUM PROCD : %d\n"
2046 "CE DBELL : 0x%x\n"
2047 "NUM DBELL FIRED : %d\n"
2048 "COMP RNG FULL : %d\n"
2049 "COMP RNG EMPT : %d\n"
2050 "COMP RNG USE HGH : %d\n"
2051 "COMP RNG USE LOW : %d\n"
2052 "BAM FIFO FULL : %d\n"
2053 "BAM FIFO EMPT : %d\n"
2054 "BAM FIFO USE HGH : %d\n"
2055 "BAM FIFO USE LOW : %d\n"
2056 "NUM DBELL : %d\n"
2057 "NUM UNEXP DBELL : %d\n"
2058 "NUM BAM INT HDL : 0x%x\n"
2059 "NUM BAM INT NON-RUN : 0x%x\n"
2060 "NUM QMB INT HDL : 0x%x",
2061 ipa_stat.tx_ch_stats.num_pkts_processed,
2062 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2063 ipa_stat.tx_ch_stats.num_db_fired,
2064 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2065 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2066 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2067 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2068 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2069 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2070 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2071 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2072 ipa_stat.tx_ch_stats.num_db,
2073 ipa_stat.tx_ch_stats.num_unexpected_db,
2074 ipa_stat.tx_ch_stats.num_bam_int_handled,
2075 ipa_stat.tx_ch_stats.
2076 num_bam_int_in_non_runnning_state,
2077 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2078
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302079 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002080 "==== IPA_UC IPA RX ====\n"
2081 "MAX OST PKT : %d\n"
2082 "NUM PKT PRCSD : %d\n"
2083 "RNG RP : 0x%x\n"
2084 "COMP RNG FULL : %d\n"
2085 "COMP RNG EMPT : %d\n"
2086 "COMP RNG USE HGH : %d\n"
2087 "COMP RNG USE LOW : %d\n"
2088 "BAM FIFO FULL : %d\n"
2089 "BAM FIFO EMPT : %d\n"
2090 "BAM FIFO USE HGH : %d\n"
2091 "BAM FIFO USE LOW : %d\n"
2092 "NUM DB : %d\n"
2093 "NUM UNEXP DB : %d\n"
2094 "NUM BAM INT HNDL : 0x%x\n",
2095 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2096 ipa_stat.rx_ch_stats.num_pkts_processed,
2097 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2098 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2099 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2100 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2101 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2102 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2103 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2104 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2105 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2106 ipa_stat.rx_ch_stats.num_db,
2107 ipa_stat.rx_ch_stats.num_unexpected_db,
2108 ipa_stat.rx_ch_stats.num_bam_int_handled);
2109 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2110 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2111 /* STATs from FW */
2112 uc_fw_stat = (struct ipa_uc_fw_stats *)
2113 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302114 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002115 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2116 uc_fw_stat->tx_pkts_completed,
2117 hdd_ipa->ipa_p_tx_packets);
2118 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2119 (uc_fw_stat->rx_num_ind_drop_no_space +
2120 uc_fw_stat->rx_num_ind_drop_no_buf +
2121 uc_fw_stat->rx_num_pkts_indicated),
2122 hdd_ipa->ipa_p_rx_packets);
2123
2124 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2125 hdd_ipa->ipa_p_rx_packets =
2126 (uc_fw_stat->rx_num_ind_drop_no_space +
2127 uc_fw_stat->rx_num_ind_drop_no_buf +
2128 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302129 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002130 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2131 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2132 hdd_ipa_uc_loaded_handler(hdd_ipa);
2133 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002134 } else {
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002135 HDD_IPA_LOG(LOGE, "INVALID REASON %d",
2136 hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002137 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302138 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002139}
2140
2141
2142/**
2143 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2144 * @adapter: device adapter instance
2145 * @offload_type: MCC or SCC
2146 * @enable: TX offload enable or disable
2147 *
2148 * Return: none
2149 */
2150static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002151 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002153 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002154 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002155 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002156 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002157
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002158 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002159 return;
2160
Yun Park8292dcb2016-10-07 16:46:06 -07002161 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002162 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002163
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002164 if (!iface_context) {
2165 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2166 "Interface context is NULL");
2167 return;
2168 }
2169
2170 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002171 /* IPA offload status is already set as desired */
2172 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002173 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
2174 "IPA offload status is already set",
2175 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002176 return;
2177 }
2178
Yun Park4540e862016-11-10 16:30:06 -08002179 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2180 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2181 "invalid session id: %d, offload_type=%d, enable=%d",
2182 adapter->sessionId, offload_type, enable);
2183 return;
2184 }
2185
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302186 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002187 sizeof(ipa_offload_enable_disable));
2188 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002189 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002190 ipa_offload_enable_disable.enable = enable;
2191
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302192 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07002193 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 ipa_offload_enable_disable.offload_type,
2195 ipa_offload_enable_disable.vdev_id,
2196 ipa_offload_enable_disable.enable);
2197
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302198 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002199 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2200 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302201 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002202 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2203 __func__,
2204 ipa_offload_enable_disable.offload_type,
2205 ipa_offload_enable_disable.vdev_id,
2206 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002207 } else {
2208 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002209 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002210 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211 }
2212}
2213
2214/**
2215 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2216 * @work: uC OP work
2217 *
2218 * Return: None
2219 */
2220static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2221{
2222 struct op_msg_type *msg;
2223 struct uc_op_work_struct *uc_op_work = container_of(work,
2224 struct uc_op_work_struct, work);
2225 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2226
2227 cds_ssr_protect(__func__);
2228
2229 msg = uc_op_work->msg;
2230 uc_op_work->msg = NULL;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302231 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002232 "%s, posted msg %d", __func__, msg->op_code);
2233
2234 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2235
2236 cds_ssr_unprotect(__func__);
2237
2238 return;
2239}
2240
2241/**
2242 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2243 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2244 * @op_msg: operation message received from firmware
2245 * @hdd_ctx: Global HDD context
2246 *
2247 * Return: None
2248 */
2249static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2250{
2251 struct hdd_ipa_priv *hdd_ipa;
2252 struct op_msg_type *msg;
2253 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302254 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002255
2256 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302257 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002258 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002259
2260 msg = (struct op_msg_type *)op_msg;
2261 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2262
2263 if (unlikely(!hdd_ipa))
2264 goto end;
2265
2266 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302267 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002268 __func__, msg->op_code);
2269 goto end;
2270 }
2271
2272 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2273 if (uc_op_work->msg)
2274 /* When the same uC OPCODE is already pended, just return */
2275 goto end;
2276
2277 uc_op_work->msg = msg;
2278 schedule_work(&uc_op_work->work);
2279 return;
2280
2281end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302282 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002283}
2284
2285/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002286 * hdd_ipa_init_uc_op_work - init ipa uc op work
2287 * @work: struct work_struct
2288 * @work_handler: work_handler
2289 *
2290 * Return: none
2291 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002292static void hdd_ipa_init_uc_op_work(struct work_struct *work,
2293 work_func_t work_handler)
2294{
2295 INIT_WORK(work, work_handler);
2296}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002297
2298
2299/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002300 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2301 * @hdd_ctx: Global HDD context
2302 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302303 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002304 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002305QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002306{
2307 struct ipa_wdi_in_params pipe_in;
2308 struct ipa_wdi_out_params pipe_out;
2309 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002310 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07002311 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002312 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2313 int ret;
2314 QDF_STATUS stat = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002315
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002316 ENTER();
2317
Yun Parkbaa62862017-01-18 13:43:34 -08002318 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002319 if (!pdev || !soc) {
2320 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkbaa62862017-01-18 13:43:34 -08002321 stat = QDF_STATUS_E_FAILURE;
2322 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002323 }
Yun Parkbaa62862017-01-18 13:43:34 -08002324
2325 cdp_ipa_get_resource(soc, (void *)pdev, &ipa_ctxt->ipa_resource);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002326 if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) ||
2327 (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2328 (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2329 (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2330 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2331 "IPA UC resource alloc fail");
2332 return QDF_STATUS_E_FAILURE;
2333 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002334 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2335 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302336 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2337 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002338
Anurag Chouhanffb21542016-02-17 14:33:03 +05302339 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302340
2341 if (!cds_is_driver_recovering()) {
2342 qdf_mutex_create(&ipa_ctxt->event_lock);
2343 qdf_mutex_create(&ipa_ctxt->ipa_lock);
2344 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002345
2346 /* TX PIPE */
2347 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2348 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2349 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2350 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2351 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2352 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2353 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2354 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2355 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2356 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2357 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2358 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2359 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302360 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Parkbaa62862017-01-18 13:43:34 -08002361 "IPA RM DISABLED, IPA AWAKE");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002362 pipe_in.sys.keep_ipa_awake = true;
2363 }
2364
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002365 pipe_in.u.dl.comp_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002366 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002367 pipe_in.u.dl.comp_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002368 ipa_ctxt->ipa_resource.tx_comp_ring_size *
2369 sizeof(qdf_dma_addr_t);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002370 pipe_in.u.dl.ce_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002371 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002372 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
2373 pipe_in.u.dl.ce_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002374 ipa_ctxt->ipa_resource.ce_sr_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002375 pipe_in.u.dl.num_tx_buffers =
Yun Parkbaa62862017-01-18 13:43:34 -08002376 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002377
Yun Parkbaa62862017-01-18 13:43:34 -08002378 qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in,
2379 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002380 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08002381 IPA_CLIENT_WLAN1_CONS);
2382
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002383 if (true == ipa_ctxt->uc_loaded) {
2384 /* Connect WDI IPA PIPE */
Yun Parkbaa62862017-01-18 13:43:34 -08002385 ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2386 if (ret) {
2387 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2388 "ipa_connect_wdi_pipe falied for Tx: ret=%d",
2389 ret);
2390 stat = QDF_STATUS_E_FAILURE;
2391 goto fail_return;
2392 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002393 /* Micro Controller Doorbell register */
Yun Parkbaa62862017-01-18 13:43:34 -08002394 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2395 "CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
2396 (unsigned int)pipe_out.uc_door_bell_pa,
2397 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002398
2399 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Yun Parkbaa62862017-01-18 13:43:34 -08002400
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002401 /* WLAN TX PIPE Handle */
2402 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2403 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Yun Parkbaa62862017-01-18 13:43:34 -08002404 "TX : 0x%x, %d, 0x%x, 0x%x, %d, %d, 0x%x",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002405 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
2406 pipe_in.u.dl.comp_ring_size,
2407 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
2408 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
2409 pipe_in.u.dl.ce_ring_size,
2410 pipe_in.u.dl.num_tx_buffers,
2411 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
2412 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002413
2414 /* RX PIPE */
2415 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2416 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
2417 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
2418 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
2419 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2420 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
2421 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
2422 sizeof(struct sps_iovec);
2423 pipe_in.sys.notify = hdd_ipa_w2i_cb;
2424 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302425 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkbaa62862017-01-18 13:43:34 -08002426 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002427 pipe_in.sys.keep_ipa_awake = true;
2428 }
2429
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002430 pipe_in.u.ul.rdy_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002431 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002432 pipe_in.u.ul.rdy_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002433 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002434 pipe_in.u.ul.rdy_ring_rp_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002435 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002436 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Yun Parkbaa62862017-01-18 13:43:34 -08002437
2438 qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in,
2439 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002440 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08002441 IPA_CLIENT_WLAN1_PROD);
2442
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002443 if (true == ipa_ctxt->uc_loaded) {
Yun Parkbaa62862017-01-18 13:43:34 -08002444 ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2445 if (ret) {
2446 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2447 "ipa_connect_wdi_pipe falied for Rx: ret=%d",
2448 ret);
2449 stat = QDF_STATUS_E_FAILURE;
2450 goto fail_return;
2451
2452 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002453 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2454 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Yun Parkbaa62862017-01-18 13:43:34 -08002455 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2456 "PROD DB pipe out 0x%x TX PIPE Handle 0x%x",
2457 (unsigned int)pipe_out.uc_door_bell_pa,
2458 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002459 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2460 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
2461 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
2462 pipe_in.u.ul.rdy_ring_size,
2463 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
2464 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
2465 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002466
Yun Parkbaa62862017-01-18 13:43:34 -08002467 cdp_ipa_set_doorbell_paddr(soc, (void *)pdev,
2468 ipa_ctxt->tx_comp_doorbell_paddr,
2469 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002470
Yun Parkbaa62862017-01-18 13:43:34 -08002471 cdp_ipa_register_op_cb(soc, (void *)pdev,
2472 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
2473
2474 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2475 "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x",
2476 pdev->ipa_uc_op_cb,
2477 (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr,
2478 (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002479
2480 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08002481 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Yun Parkbaa62862017-01-18 13:43:34 -08002482 hdd_ipa_uc_fw_op_event_handler);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002483 ipa_ctxt->uc_op_work[i].msg = NULL;
2484 }
2485
Yun Parkbaa62862017-01-18 13:43:34 -08002486fail_return:
2487 EXIT();
2488 return stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002489}
2490
Leo Change3e49442015-10-26 20:07:13 -07002491/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002492 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002493 * @hdd_ctx: hdd main context
2494 *
2495 * Force shutdown IPA pipe
2496 * Independent of FW pipe status, IPA pipe shutdonw progress
2497 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2498 * independent from FW pipe status
2499 *
2500 * Return: NONE
2501 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002502static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002503{
2504 struct hdd_ipa_priv *hdd_ipa;
2505
2506 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2507 return;
2508
2509 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2510 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302511 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07002512 "IPA pipes are not down yet, force shutdown");
2513 hdd_ipa_uc_disable_pipes(hdd_ipa);
2514 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302515 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Leo Change3e49442015-10-26 20:07:13 -07002516 "IPA pipes are down, do nothing");
2517 }
2518
2519 return;
2520}
2521
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002522/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002523 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2524 * __hdd_ipa_uc_force_pipe_shutdown
2525 * @hdd_ctx: hdd main context
2526 *
2527 * Force shutdown IPA pipe
2528 * Independent of FW pipe status, IPA pipe shutdonw progress
2529 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2530 * independent from FW pipe status
2531 *
2532 * Return: NONE
2533 */
2534void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2535{
2536 cds_ssr_protect(__func__);
2537 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2538 cds_ssr_unprotect(__func__);
2539}
2540
2541/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302542 * hdd_ipa_msg_free_fn() - Free an IPA message
2543 * @buff: pointer to the IPA message
2544 * @len: length of the IPA message
2545 * @type: type of IPA message
2546 *
2547 * Return: None
2548 */
2549static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2550{
2551 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "msg type:%d, len:%d", type, len);
2552 ghdd_ipa->stats.num_free_msg++;
2553 qdf_mem_free(buff);
2554}
2555
Govind Singh9c58eba2016-09-02 16:23:06 +05302556/**
jge62037862016-12-09 10:44:33 +08002557 * hdd_ipa_uc_send_evt() - send event to ipa
2558 * @hdd_ctx: pointer to hdd context
2559 * @type: event type
2560 * @mac_addr: pointer to mac address
2561 *
2562 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05302563 *
2564 * Return: 0 - Success
2565 */
jge62037862016-12-09 10:44:33 +08002566static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
2567 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05302568{
jge62037862016-12-09 10:44:33 +08002569 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05302570 struct ipa_msg_meta meta;
2571 struct ipa_wlan_msg *msg;
2572 int ret = 0;
jge62037862016-12-09 10:44:33 +08002573
2574 meta.msg_len = sizeof(struct ipa_wlan_msg);
2575 msg = qdf_mem_malloc(meta.msg_len);
2576 if (msg == NULL) {
2577 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2578 "msg allocation failed");
2579 return -ENOMEM;
2580 }
2581
2582 meta.msg_type = type;
2583 strlcpy(msg->name, adapter->dev->name,
2584 IPA_RESOURCE_NAME_MAX);
2585 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
2586 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
2587 msg->name, meta.msg_type);
2588 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2589 if (ret) {
2590 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2591 "%s: Evt: %d fail:%d",
2592 msg->name, meta.msg_type, ret);
2593 qdf_mem_free(msg);
2594 return ret;
2595 }
2596
2597 hdd_ipa->stats.num_send_msg++;
2598
2599 return ret;
2600}
2601
2602/**
2603 * hdd_ipa_uc_disconnect_client() - send client disconnect event
2604 * @hdd_ctx: pointer to hdd adapter
2605 *
2606 * Send disconnect client event to IPA driver during SSR
2607 *
2608 * Return: 0 - Success
2609 */
2610static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
2611{
2612 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2613 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05302614 int i;
2615
2616 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2617 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2618 continue;
2619 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08002620 (!adapter->aStaInfo[i].isDeauthInProgress) &&
2621 hdd_ipa->sap_num_connected_sta) {
2622 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
2623 adapter->aStaInfo[i].macAddrSTA.bytes);
2624 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05302625 }
2626 }
2627
2628 return ret;
2629}
2630
2631/**
jge62037862016-12-09 10:44:33 +08002632 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
2633 * @hdd_ctx: pointer to hdd adapter
2634 *
2635 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05302636 *
2637 * Return: 0 - Success
2638 */
jge62037862016-12-09 10:44:33 +08002639
2640static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
2641{
2642 int ret = 0;
2643
2644 if (adapter->ipa_context)
2645 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
2646 adapter->dev->dev_addr);
2647
2648 return ret;
2649}
2650
jge62037862016-12-09 10:44:33 +08002651/**
2652 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
2653 * @hdd_ctx: pointer to hdd adapter
2654 *
2655 * Send disconnect sta event to IPA driver during SSR
2656 *
2657 * Return: 0 - Success
2658 */
2659static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2660{
2661 hdd_station_ctx_t *pHddStaCtx;
2662 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2663 int ret = 0;
2664
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002665 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08002666 hdd_ipa->sta_connected) {
2667 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2668 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002669 pHddStaCtx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08002670 }
2671
2672 return ret;
2673}
jge62037862016-12-09 10:44:33 +08002674
2675/**
2676 * hdd_ipa_uc_disconnect() - send disconnect ipa event
2677 * @hdd_ctx: pointer to hdd context
2678 *
2679 * Send disconnect event to IPA driver during SSR
2680 *
2681 * Return: 0 - Success
2682 */
2683static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05302684{
2685 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2686 QDF_STATUS status;
2687 hdd_adapter_t *adapter;
2688 int ret = 0;
2689
Govind Singh9c58eba2016-09-02 16:23:06 +05302690 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2691 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2692 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08002693 if (adapter->device_mode == QDF_SAP_MODE) {
2694 hdd_ipa_uc_disconnect_client(adapter);
2695 hdd_ipa_uc_disconnect_ap(adapter);
2696 } else if (adapter->device_mode == QDF_STA_MODE) {
2697 hdd_ipa_uc_disconnect_sta(adapter);
2698 }
2699
Govind Singh9c58eba2016-09-02 16:23:06 +05302700 status = hdd_get_next_adapter(
2701 hdd_ctx, adapter_node, &next);
2702 adapter_node = next;
2703 }
2704
2705 return ret;
2706}
2707
2708/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002709 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002710 *
2711 * Deinit basic IPA UC host side to be in sync reloaded FW during
2712 * SSR
2713 *
2714 * Return: 0 - Success
2715 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002716static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002717{
2718 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2719 int idx;
2720 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302721 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002722
Arun Khandavallicc544b32017-01-30 19:52:16 +05302723 if (!hdd_ipa)
2724 return 0;
2725
2726 hdd_ctx = hdd_ipa->hdd_ctx;
2727 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002728 return 0;
2729
jge62037862016-12-09 10:44:33 +08002730 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302731 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08002732
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002733 /* Clean up HDD IPA interfaces */
2734 for (idx = 0; (hdd_ipa->num_iface > 0) &&
2735 (idx < HDD_IPA_MAX_IFACE); idx++) {
2736 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08002737 if (iface_context->adapter && iface_context->adapter->magic ==
2738 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002739 hdd_ipa_cleanup_iface(iface_context);
2740 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08002741 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742 /* After SSR, wlan driver reloads FW again. But we need to protect
2743 * IPA submodule during SSR transient state. So deinit basic IPA
2744 * UC host side to be in sync with reloaded FW during SSR
2745 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08002746 if (!hdd_ipa->ipa_pipes_down)
2747 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002748
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302749 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002750 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2751 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
2752 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
2753 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302754 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002755
Arun Khandavallicc544b32017-01-30 19:52:16 +05302756 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2757 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
2758 __func__, hdd_ipa->tx_pipe_handle);
2759 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
2760
2761 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2762 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
2763 __func__, hdd_ipa->rx_pipe_handle);
2764 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
2765
Guolei Bianca144d82016-11-10 11:07:42 +08002766 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
2767 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
2768
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002769 /* Full IPA driver cleanup not required since wlan driver is now
2770 * unloaded and reloaded after SSR.
2771 */
2772 return 0;
2773}
2774
2775/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002776 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
2777 *
2778 * Deinit basic IPA UC host side to be in sync reloaded FW during
2779 * SSR
2780 *
2781 * Return: 0 - Success
2782 */
2783int hdd_ipa_uc_ssr_deinit(void)
2784{
2785 int ret;
2786
2787 cds_ssr_protect(__func__);
2788 ret = __hdd_ipa_uc_ssr_deinit();
2789 cds_ssr_unprotect(__func__);
2790
2791 return ret;
2792}
2793
2794/**
2795 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002796 *
2797 * Init basic IPA UC host side to be in sync with reloaded FW after
2798 * SSR to resume IPA UC operations
2799 *
2800 * Return: 0 - Success
2801 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302802static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002803{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002804
Arun Khandavallicc544b32017-01-30 19:52:16 +05302805 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2806 int i;
2807 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302808
2809 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
2810 return 0;
2811
Arun Khandavallicc544b32017-01-30 19:52:16 +05302812 /* Create the interface context */
2813 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2814 iface_context = &hdd_ipa->iface_context[i];
2815 iface_context->hdd_ipa = hdd_ipa;
2816 iface_context->cons_client =
2817 hdd_ipa_adapter_2_client[i].cons_client;
2818 iface_context->prod_client =
2819 hdd_ipa_adapter_2_client[i].prod_client;
2820 iface_context->iface_id = i;
2821 iface_context->adapter = NULL;
2822 }
2823 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
2824 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
2825 hdd_ipa->vdev_offload_enabled[i] = false;
2826 }
2827
2828 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2829 hdd_ipa->resource_loading = false;
2830 hdd_ipa->resource_unloading = false;
2831 hdd_ipa->sta_connected = 0;
2832 hdd_ipa->ipa_pipes_down = true;
2833 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302834 }
2835
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836 return 0;
2837}
Leo Chang3bc8fed2015-11-13 10:59:47 -08002838
2839/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002840 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
2841 *
2842 * Init basic IPA UC host side to be in sync with reloaded FW after
2843 * SSR to resume IPA UC operations
2844 *
2845 * Return: 0 - Success
2846 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302847int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002848{
2849 int ret;
2850
2851 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302852 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002853 cds_ssr_unprotect(__func__);
2854
2855 return ret;
2856}
2857
2858/**
2859 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08002860 * @hdd_ctx: Global HDD context
2861 * @skb: skb sent to IPA
2862 * @session_id: send packet instance session id
2863 *
2864 * Send TX packet which generated by system to IPA.
2865 * This routine only will be used for function verification
2866 *
2867 * Return: NULL packet sent to IPA properly
2868 * NULL invalid packet drop
2869 * skb packet not sent to IPA. legacy data path should handle
2870 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002871static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002872 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07002873{
Leo Chang3bc8fed2015-11-13 10:59:47 -08002874 struct ipa_header *ipa_header;
2875 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002876 struct hdd_ipa_priv *hdd_ipa;
2877
2878 if (wlan_hdd_validate_context(hdd_ctx))
2879 return skb;
2880
2881 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002882
2883 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2884 return skb;
2885
Leo Chang07b28f62016-05-11 12:29:22 -07002886 if (!hdd_ipa)
2887 return skb;
2888
2889 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
2890 return skb;
2891
Leo Changcc923e22016-06-16 15:29:03 -07002892 if (skb_headroom(skb) <
2893 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07002894 return skb;
2895
Leo Chang3bc8fed2015-11-13 10:59:47 -08002896 ipa_header = (struct ipa_header *) skb_push(skb,
2897 sizeof(struct ipa_header));
2898 if (!ipa_header) {
2899 /* No headroom, legacy */
2900 return skb;
2901 }
2902 memset(ipa_header, 0, sizeof(*ipa_header));
2903 ipa_header->vdev_id = 0;
2904
2905 frag_header = (struct frag_header *) skb_push(skb,
2906 sizeof(struct frag_header));
2907 if (!frag_header) {
2908 /* No headroom, drop */
2909 kfree_skb(skb);
2910 return NULL;
2911 }
2912 memset(frag_header, 0, sizeof(*frag_header));
2913 frag_header->length = skb->len - sizeof(struct frag_header)
2914 - sizeof(struct ipa_header);
2915
2916 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
2917 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07002918}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002919
2920/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002921 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
2922 * @hdd_ctx: Global HDD context
2923 * @skb: skb sent to IPA
2924 * @session_id: send packet instance session id
2925 *
2926 * Send TX packet which generated by system to IPA.
2927 * This routine only will be used for function verification
2928 *
2929 * Return: NULL packet sent to IPA properly
2930 * NULL invalid packet drop
2931 * skb packet not sent to IPA. legacy data path should handle
2932 */
2933struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
2934 struct sk_buff *skb, uint8_t session_id)
2935{
2936 struct sk_buff *ret;
2937
2938 cds_ssr_protect(__func__);
2939 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
2940 cds_ssr_unprotect(__func__);
2941
2942 return ret;
2943}
2944
2945/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002946 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
2947 * @work: scheduled work
2948 *
2949 * When IPA resources are released in hdd_ipa_rm_try_release() we do
2950 * not want to immediately release the wake lock since the system
2951 * would then potentially try to suspend when there is a healthy data
2952 * rate. Deferred work is scheduled and this function handles the
2953 * work. When this function is called, if the IPA resource is still
2954 * released then we release the wake lock.
2955 *
2956 * Return: None
2957 */
2958static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
2959{
2960 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
2961 struct hdd_ipa_priv,
2962 wake_lock_work);
2963
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302964 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002965
2966 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
2967 goto end;
2968
2969 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302970 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002971 WIFI_POWER_EVENT_WAKELOCK_IPA);
2972
2973end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302974 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002975}
2976
2977/**
2978 * hdd_ipa_rm_request() - Request resource from IPA
2979 * @hdd_ipa: Global HDD IPA context
2980 *
2981 * Return: 0 on success, negative errno on error
2982 */
2983static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
2984{
2985 int ret = 0;
2986
2987 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2988 return 0;
2989
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302990 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002991
2992 switch (hdd_ipa->rm_state) {
2993 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302994 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002995 return 0;
2996 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302997 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002998 return -EINPROGRESS;
2999 case HDD_IPA_RM_RELEASED:
3000 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3001 break;
3002 }
3003
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303004 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003005
3006 ret = ipa_rm_inactivity_timer_request_resource(
3007 IPA_RM_RESOURCE_WLAN_PROD);
3008
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303009 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003010 if (ret == 0) {
3011 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3012 hdd_ipa->stats.num_rm_grant_imm++;
3013 }
3014
3015 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3016 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303017 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 WIFI_POWER_EVENT_WAKELOCK_IPA);
3019 hdd_ipa->wake_lock_released = false;
3020 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303021 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003022
3023 return ret;
3024}
3025
3026/**
3027 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3028 * @hdd_ipa: Global HDD IPA context
3029 *
3030 * Return: 0 if resources released, negative errno otherwise
3031 */
3032static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3033{
3034 int ret = 0;
3035
3036 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3037 return 0;
3038
3039 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3040 return -EAGAIN;
3041
3042 spin_lock_bh(&hdd_ipa->q_lock);
3043 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
3044 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
3045 spin_unlock_bh(&hdd_ipa->q_lock);
3046 return -EAGAIN;
3047 }
3048 spin_unlock_bh(&hdd_ipa->q_lock);
3049
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303050 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003051
Nirav Shahcbc6d722016-03-01 16:24:53 +05303052 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303053 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003054 return -EAGAIN;
3055 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303056 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003057
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303058 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003059 switch (hdd_ipa->rm_state) {
3060 case HDD_IPA_RM_GRANTED:
3061 break;
3062 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303063 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003064 return -EINPROGRESS;
3065 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303066 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003067 return 0;
3068 }
3069
3070 /* IPA driver returns immediately so set the state here to avoid any
3071 * race condition.
3072 */
3073 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3074 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303075 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003076
3077 ret =
3078 ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
3079
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303080 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003081 if (unlikely(ret != 0)) {
3082 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3083 WARN_ON(1);
3084 }
3085
3086 /*
3087 * If wake_lock is released immediately, kernel would try to suspend
3088 * immediately as well, Just avoid ping-pong between suspend-resume
3089 * while there is healthy amount of data transfer going on by
3090 * releasing the wake_lock after some delay.
3091 */
3092 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3093 msecs_to_jiffies
3094 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3095
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303096 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003097
3098 return ret;
3099}
3100
3101/**
3102 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3103 * @user_data: user data registered with IPA
3104 * @event: the IPA resource manager event that occurred
3105 * @data: the data associated with the event
3106 *
3107 * Return: None
3108 */
3109static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3110 unsigned long data)
3111{
3112 struct hdd_ipa_priv *hdd_ipa = user_data;
3113
3114 if (unlikely(!hdd_ipa))
3115 return;
3116
3117 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3118 return;
3119
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303120 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003121
3122 switch (event) {
3123 case IPA_RM_RESOURCE_GRANTED:
3124 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3125 /* RM Notification comes with ISR context
3126 * it should be serialized into work queue to avoid
3127 * ISR sleep problem
3128 */
3129 hdd_ipa->uc_rm_work.event = event;
3130 schedule_work(&hdd_ipa->uc_rm_work.work);
3131 break;
3132 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303133 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003134 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303135 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003136 hdd_ipa->stats.num_rm_grant++;
3137 break;
3138
3139 case IPA_RM_RESOURCE_RELEASED:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303140 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003141 hdd_ipa->resource_unloading = false;
3142 break;
3143
3144 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303145 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003146 break;
3147 }
3148}
3149
3150/**
3151 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3152 *
3153 * Callback function registered with IPA that is called when IPA wants
3154 * to release the WLAN consumer resource
3155 *
3156 * Return: 0 if the request is granted, negative errno otherwise
3157 */
3158static int hdd_ipa_rm_cons_release(void)
3159{
3160 return 0;
3161}
3162
3163/**
3164 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3165 *
3166 * Callback function registered with IPA that is called when IPA wants
3167 * to access the WLAN consumer resource
3168 *
3169 * Return: 0 if the request is granted, negative errno otherwise
3170 */
3171static int hdd_ipa_rm_cons_request(void)
3172{
Yun Park4d8b60a2015-10-22 13:59:32 -07003173 int ret = 0;
3174
3175 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303176 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003177 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003178 __func__);
3179 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003180 ret = -EINPROGRESS;
3181 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303182 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003183 "%s: IPA resource unloading in progress",
3184 __func__);
3185 ghdd_ipa->pending_cons_req = true;
3186 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003187 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003188
3189 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003190}
3191
3192/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003193 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003194 * @hdd_ctx: Global HDD context
3195 * @tx_packets: Number of packets transmitted in the last sample period
3196 * @rx_packets: Number of packets received in the last sample period
3197 *
3198 * Return: 0 on success, negative errno on error
3199 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003200static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003201 uint64_t rx_packets)
3202{
3203 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003204 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003205 struct ipa_rm_perf_profile profile;
3206 int ret;
3207
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003208 if (wlan_hdd_validate_context(hdd_ctx))
3209 return 0;
3210
3211 hdd_ipa = hdd_ctx->hdd_ipa;
3212
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003213 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3214 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3215 return 0;
3216
3217 memset(&profile, 0, sizeof(profile));
3218
3219 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3220 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3221 else if (tx_packets >
3222 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3223 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3224 else
3225 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3226
3227 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3228 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3229 else if (rx_packets >
3230 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3231 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3232 else
3233 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3234
Yun Park8f289c82016-10-18 16:38:21 -07003235 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003236 "CONS perf curr: %d, next: %d",
3237 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Park8f289c82016-10-18 16:38:21 -07003238 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003239 "PROD perf curr: %d, next: %d",
3240 hdd_ipa->curr_prod_bw, next_prod_bw);
3241
3242 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003243 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003244 hdd_ipa->curr_cons_bw, next_cons_bw);
3245 profile.max_supported_bandwidth_mbps = next_cons_bw;
3246 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3247 &profile);
3248 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003249 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003250
3251 return ret;
3252 }
3253 hdd_ipa->curr_cons_bw = next_cons_bw;
3254 hdd_ipa->stats.num_cons_perf_req++;
3255 }
3256
3257 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003258 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003259 hdd_ipa->curr_prod_bw, next_prod_bw);
3260 profile.max_supported_bandwidth_mbps = next_prod_bw;
3261 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3262 &profile);
3263 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003264 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003265 return ret;
3266 }
3267 hdd_ipa->curr_prod_bw = next_prod_bw;
3268 hdd_ipa->stats.num_prod_perf_req++;
3269 }
3270
3271 return 0;
3272}
3273
3274/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003275 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3276 * @hdd_ctx: Global HDD context
3277 * @tx_packets: Number of packets transmitted in the last sample period
3278 * @rx_packets: Number of packets received in the last sample period
3279 *
3280 * Return: 0 on success, negative errno on error
3281 */
3282int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3283 uint64_t rx_packets)
3284{
3285 int ret;
3286
3287 cds_ssr_protect(__func__);
3288 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3289 cds_ssr_unprotect(__func__);
3290
3291 return ret;
3292}
3293
3294/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003295 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3296 * @work: struct work_struct
3297 * @work_handler: work_handler
3298 *
3299 * Return: none
3300 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003301static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3302 work_func_t work_handler)
3303{
3304 INIT_WORK(work, work_handler);
3305}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003306
3307/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003308 * hdd_ipa_setup_rm() - Setup IPA resource management
3309 * @hdd_ipa: Global HDD IPA context
3310 *
3311 * Return: 0 on success, negative errno on error
3312 */
3313static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3314{
3315 struct ipa_rm_create_params create_params = { 0 };
3316 int ret;
3317
3318 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3319 return 0;
3320
Rajeev Kumar217f2172016-01-06 18:11:55 -08003321 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3322 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003323 memset(&create_params, 0, sizeof(create_params));
3324 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3325 create_params.reg_params.user_data = hdd_ipa;
3326 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3327 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3328
3329 ret = ipa_rm_create_resource(&create_params);
3330 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303331 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003332 "Create RM resource failed: %d", ret);
3333 goto setup_rm_fail;
3334 }
3335
3336 memset(&create_params, 0, sizeof(create_params));
3337 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3338 create_params.request_resource = hdd_ipa_rm_cons_request;
3339 create_params.release_resource = hdd_ipa_rm_cons_release;
3340 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3341
3342 ret = ipa_rm_create_resource(&create_params);
3343 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303344 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003345 "Create RM CONS resource failed: %d", ret);
3346 goto delete_prod;
3347 }
3348
3349 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3350 IPA_RM_RESOURCE_APPS_CONS);
3351
3352 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3353 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3354 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303355 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003356 ret);
3357 goto timer_init_failed;
3358 }
3359
3360 /* Set the lowest bandwidth to start with */
3361 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3362
3363 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303364 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003365 "Set perf level failed: %d", ret);
3366 goto set_perf_failed;
3367 }
3368
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303369 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003370 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3371 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303372 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003373 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3374 hdd_ipa->wake_lock_released = true;
3375 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3376
3377 return ret;
3378
3379set_perf_failed:
3380 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3381
3382timer_init_failed:
3383 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3384
3385delete_prod:
3386 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3387
3388setup_rm_fail:
3389 return ret;
3390}
3391
3392/**
3393 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3394 * @hdd_ipa: Global HDD IPA context
3395 *
3396 * Destroys all resources associated with the IPA resource manager
3397 *
3398 * Return: None
3399 */
3400static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3401{
3402 int ret;
3403
3404 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3405 return;
3406
3407 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303408 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003409
3410#ifdef WLAN_OPEN_SOURCE
3411 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
3412#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303413 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003414
3415 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3416
3417 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3418 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303419 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003420 "RM PROD resource delete failed %d", ret);
3421
3422 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3423 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303424 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003425 "RM CONS resource delete failed %d", ret);
3426}
3427
3428/**
3429 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3430 * @skb: network buffer
3431 * @adapter: network adapter
3432 *
3433 * Called when a network buffer is received which should not be routed
3434 * to the IPA module.
3435 *
3436 * Return: None
3437 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303438static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003439 hdd_adapter_t *adapter)
3440{
3441 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3442 unsigned int cpu_index;
3443
3444 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303445 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003446 adapter);
3447 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003448 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003449 return;
3450 }
3451
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003452 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003453 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003454 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003455 return;
3456 }
3457
3458 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3459 skb->dev = adapter->dev;
3460 skb->protocol = eth_type_trans(skb, skb->dev);
3461 skb->ip_summed = CHECKSUM_NONE;
3462
3463 cpu_index = wlan_hdd_get_cpu();
3464
3465 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
3466 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
3467 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3468 else
3469 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3470
3471 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
3472 adapter->dev->last_rx = jiffies;
3473}
3474
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003475/**
Leo Chang69c39692016-10-12 20:11:12 -07003476 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3477 * @hdd_ipa: pointer to hdd ipa context
3478 * @adapter: network adapter
3479 * @skb: data pointer
3480 *
3481 * if exception packet has set forward bit, copied new packet should be
3482 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3483 * put into pm queue and tx procedure will be differed
3484 *
3485 * Return: None
3486 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003487static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
3488 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003489{
Leo Chang69c39692016-10-12 20:11:12 -07003490 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3491
Leo Chang69c39692016-10-12 20:11:12 -07003492 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
3493 /* WLAN subsystem is in suspend, put int queue */
3494 if (hdd_ipa->suspended) {
3495 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3496 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3497 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003498 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3499 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003500 pm_tx_cb->exception = true;
3501 pm_tx_cb->adapter = adapter;
3502 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003503 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003504 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3505 hdd_ipa->stats.num_tx_queued++;
3506 } else {
3507 /* Resume, put packet into WLAN TX */
3508 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003509 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003510 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3511 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003512 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003513 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003514 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003515 hdd_ipa->ipa_tx_forward++;
3516 }
3517 }
3518}
3519
3520/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003521 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3522 * @hdd_ipa: pointer to HDD IPA struct
3523 * @adapter: hdd adapter pointer
3524 * @desc: Firmware descriptor
3525 * @skb: Data buffer
3526 *
3527 * Return:
3528 * HDD_IPA_FORWARD_PKT_NONE
3529 * HDD_IPA_FORWARD_PKT_DISCARD
3530 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3531 *
3532 */
3533
3534static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3535 struct hdd_ipa_priv *hdd_ipa,
3536 hdd_adapter_t *adapter,
3537 uint8_t desc,
3538 qdf_nbuf_t skb)
3539{
3540 int ret = HDD_IPA_FORWARD_PKT_NONE;
3541
3542 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303543 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003544 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
3545 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303546 /* Drop the packet*/
3547 hdd_ipa->stats.num_tx_fwd_err++;
3548 kfree_skb(skb);
3549 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3550 return ret;
3551 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003552 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3553 "Forward packet to Tx (fw_desc=%d)", desc);
3554 hdd_ipa->ipa_tx_forward++;
3555
3556 if ((desc & FW_RX_DESC_DISCARD_M)) {
3557 hdd_ipa_forward(hdd_ipa, adapter, skb);
3558 hdd_ipa->ipa_rx_internel_drop_count++;
3559 hdd_ipa->ipa_rx_discard++;
3560 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3561 } else {
3562 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
3563 if (cloned_skb)
3564 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3565 else
3566 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3567 "%s: tx skb alloc failed",
3568 __func__);
3569 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3570 }
3571 }
3572
3573 return ret;
3574}
3575
3576/**
Leo Chang69c39692016-10-12 20:11:12 -07003577 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003578 * @priv: pointer to private data registered with IPA (we register a
3579 * pointer to the global IPA context)
3580 * @evt: the IPA event which triggered the callback
3581 * @data: data associated with the event
3582 *
3583 * Return: None
3584 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003585static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003586 unsigned long data)
3587{
3588 struct hdd_ipa_priv *hdd_ipa = NULL;
3589 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303590 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003591 uint8_t iface_id;
3592 uint8_t session_id;
3593 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003594 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003595 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003596
3597 hdd_ipa = (struct hdd_ipa_priv *)priv;
3598
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003599 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3600 return;
3601
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003602 switch (evt) {
3603 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303604 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003605
3606 /*
3607 * When SSR is going on or driver is unloading,
3608 * just drop the packets.
3609 */
3610 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
3611 if (0 != status) {
3612 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3613 "Invalid context: drop packet");
3614 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3615 kfree_skb(skb);
3616 return;
3617 }
3618
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003619 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3620 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003621 iface_id = hdd_ipa->vdev_to_iface[session_id];
Govind Singhb6a89772016-08-12 11:23:35 +05303622 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003623 "IPA_RECEIVE: session_id=%u, iface_id=%u",
3624 session_id, iface_id);
3625 } else {
3626 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
3627 }
3628
3629 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303630 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003631 "IPA_RECEIVE: Invalid iface_id: %u",
3632 iface_id);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303633 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_INFO_HIGH,
Yun Parkb187d542016-11-14 18:10:04 -08003634 "w2i -- skb",
3635 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003637 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638 return;
3639 }
3640
3641 iface_context = &hdd_ipa->iface_context[iface_id];
3642 adapter = iface_context->adapter;
3643
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303644 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003645 "w2i -- skb",
3646 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003647 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3648 hdd_ipa->stats.num_rx_excep++;
3649 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
3650 } else {
3651 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
3652 }
3653
3654 iface_context->stats.num_rx_ipa_excep++;
3655
3656 /* Disable to forward Intra-BSS Rx packets when
3657 * ap_isolate=1 in hostapd.conf
3658 */
Yun Park046101c2016-09-02 15:32:14 -07003659 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003660 /*
3661 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3662 * all Rx packets to IPA uC, which need to be forwarded
3663 * to other interface.
3664 * And, IPA driver will send back to WLAN host driver
3665 * through exception pipe with fw_desc field set by FW.
3666 * Here we are checking fw_desc field for FORWARD bit
3667 * set, and forward to Tx. Then copy to kernel stack
3668 * only when DISCARD bit is not set.
3669 */
3670 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003671 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3672 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3673 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003674 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003675 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303676 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003677 "Intra-BSS FWD is disabled-skip forward to Tx");
3678 }
3679
3680 hdd_ipa_send_skb_to_network(skb, adapter);
3681 break;
3682
3683 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303684 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003685 "w2i cb wrong event: 0x%x", evt);
3686 return;
3687 }
3688}
3689
3690/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003691 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3692 * @priv: pointer to private data registered with IPA (we register a
3693 * pointer to the global IPA context)
3694 * @evt: the IPA event which triggered the callback
3695 * @data: data associated with the event
3696 *
3697 * Return: None
3698 */
3699static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3700 unsigned long data)
3701{
3702 cds_ssr_protect(__func__);
3703 __hdd_ipa_w2i_cb(priv, evt, data);
3704 cds_ssr_unprotect(__func__);
3705}
3706
3707/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708 * hdd_ipa_nbuf_cb() - IPA TX complete callback
3709 * @skb: packet buffer which was transmitted
3710 *
3711 * Return: None
3712 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303713void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003714{
3715 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3716
Govind Singhb6a89772016-08-12 11:23:35 +05303717 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05303718 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003719 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303720 ipa_free_skb((struct ipa_rx_data *)
3721 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003722
3723 hdd_ipa->stats.num_tx_comp_cnt++;
3724
3725 atomic_dec(&hdd_ipa->tx_ref_cnt);
3726
3727 hdd_ipa_rm_try_release(hdd_ipa);
3728}
3729
3730/**
3731 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
3732 * @iface_context: interface-specific IPA context
3733 * @ipa_tx_desc: packet data descriptor
3734 *
3735 * Return: None
3736 */
3737static void hdd_ipa_send_pkt_to_tl(
3738 struct hdd_ipa_iface_context *iface_context,
3739 struct ipa_rx_data *ipa_tx_desc)
3740{
3741 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003742 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303743 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003744
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303745 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003746 adapter = iface_context->adapter;
3747 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303748 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003749 ipa_free_skb(ipa_tx_desc);
3750 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303751 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003752 hdd_ipa_rm_try_release(hdd_ipa);
3753 return;
3754 }
3755
3756 /*
3757 * During CAC period, data packets shouldn't be sent over the air so
3758 * drop all the packets here
3759 */
3760 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
3761 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303762 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003763 iface_context->stats.num_tx_cac_drop++;
3764 hdd_ipa_rm_try_release(hdd_ipa);
3765 return;
3766 }
3767
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003768 ++adapter->stats.tx_packets;
3769
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303770 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003771
3772 skb = ipa_tx_desc->skb;
3773
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303774 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303775 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003776 /* FIXME: This is broken. No such field in cb any more:
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08003777 * NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb;
3778 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003779 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05303780 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003781 ipa_tx_desc->dma_addr
3782 + HDD_IPA_WLAN_FRAG_HEADER
3783 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003784 ipa_tx_desc->skb->len -=
3785 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
3786 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05303787 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003788
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003789 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303790 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791
3792 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
3793
Leo Changfdb45c32016-10-28 11:09:23 -07003794 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003795 (struct cdp_vdev *)iface_context->tl_context,
3796 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003797 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303798 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003799 ipa_free_skb(ipa_tx_desc);
3800 iface_context->stats.num_tx_err++;
3801 hdd_ipa_rm_try_release(hdd_ipa);
3802 return;
3803 }
3804
3805 atomic_inc(&hdd_ipa->tx_ref_cnt);
3806
3807 iface_context->stats.num_tx++;
3808
3809}
3810
3811/**
Leo Chang11545d62016-10-17 14:53:50 -07003812 * hdd_ipa_is_present() - get IPA hw status
3813 * @hdd_ctx: pointer to hdd context
3814 *
3815 * ipa_uc_reg_rdyCB is not directly designed to check
3816 * ipa hw status. This is an undocumented function which
3817 * has confirmed with IPA team.
3818 *
3819 * Return: true - ipa hw present
3820 * false - ipa hw not present
3821 */
3822bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
3823{
3824 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07003825 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07003826 return true;
3827 else
3828 return false;
3829}
3830
3831/**
Leo Chang69c39692016-10-12 20:11:12 -07003832 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003833 * @work: pointer to the scheduled work
3834 *
3835 * Called during PM resume to send packets to TL which were queued
3836 * while host was in the process of suspending.
3837 *
3838 * Return: None
3839 */
Leo Chang69c39692016-10-12 20:11:12 -07003840static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003841{
3842 struct hdd_ipa_priv *hdd_ipa = container_of(work,
3843 struct hdd_ipa_priv,
3844 pm_work);
3845 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303846 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003847 uint32_t dequeued = 0;
3848
Leo Chang69c39692016-10-12 20:11:12 -07003849 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
3850 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303851 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303852 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
3853 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303854 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003855
3856 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003857 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07003858 if (pm_tx_cb->exception) {
3859 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3860 "FLUSH EXCEPTION");
3861 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
3862 } else {
3863 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003864 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07003865 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303866 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003867 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303868 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07003869 qdf_wake_lock_release(&hdd_ipa->wake_lock,
3870 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003871
3872 hdd_ipa->stats.num_tx_dequeued += dequeued;
3873 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
3874 hdd_ipa->stats.num_max_pm_queue = dequeued;
3875}
3876
3877/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003878 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003879 * @priv: pointer to private data registered with IPA (we register a
3880 * pointer to the interface-specific IPA context)
3881 * @evt: the IPA event which triggered the callback
3882 * @data: data associated with the event
3883 *
3884 * Return: None
3885 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003886static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003887 unsigned long data)
3888{
3889 struct hdd_ipa_priv *hdd_ipa = NULL;
3890 struct ipa_rx_data *ipa_tx_desc;
3891 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303892 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003893 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303894 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003895
Mukul Sharma81661ae2015-10-30 20:26:02 +05303896 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003897 ipa_tx_desc = (struct ipa_rx_data *)data;
3898 hdd_ipa = iface_context->hdd_ipa;
3899
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003900 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003901 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
3902 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003903 iface_context->stats.num_tx_drop++;
3904 return;
3905 }
3906
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003907 /*
3908 * When SSR is going on or driver is unloading, just drop the packets.
3909 * During SSR, there is no use in queueing the packets as STA has to
3910 * connect back any way
3911 */
3912 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303913 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003914 ipa_free_skb(ipa_tx_desc);
3915 iface_context->stats.num_tx_drop++;
3916 return;
3917 }
3918
3919 skb = ipa_tx_desc->skb;
3920
Yun Parkb187d542016-11-14 18:10:04 -08003921 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
3922 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923
3924 /*
3925 * If PROD resource is not requested here then there may be cases where
3926 * IPA hardware may be clocked down because of not having proper
3927 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
3928 * workaround to request PROD resource while data is going over CONS
3929 * pipe to prevent the IPA hardware clockdown.
3930 */
3931 hdd_ipa_rm_request(hdd_ipa);
3932
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303933 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003934 /*
3935 * If host is still suspended then queue the packets and these will be
3936 * drained later when resume completes. When packet is arrived here and
3937 * host is suspended, this means that there is already resume is in
3938 * progress.
3939 */
3940 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303941 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003942 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
3943 pm_tx_cb->iface_context = iface_context;
3944 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303945 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003946 hdd_ipa->stats.num_tx_queued++;
3947
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303948 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003949 return;
3950 }
3951
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303952 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003953
3954 /*
3955 * If we are here means, host is not suspended, wait for the work queue
3956 * to finish.
3957 */
3958#ifdef WLAN_OPEN_SOURCE
3959 flush_work(&hdd_ipa->pm_work);
3960#endif
3961
3962 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
3963}
3964
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003965/*
3966 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
3967 * @priv: pointer to private data registered with IPA (we register a
3968 * pointer to the interface-specific IPA context)
3969 * @evt: the IPA event which triggered the callback
3970 * @data: data associated with the event
3971 *
3972 * Return: None
3973 */
3974static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
3975 unsigned long data)
3976{
3977 cds_ssr_protect(__func__);
3978 __hdd_ipa_i2w_cb(priv, evt, data);
3979 cds_ssr_unprotect(__func__);
3980}
3981
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003983 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003984 * @hdd_ctx: Global HDD context
3985 *
3986 * Return: 0 on success, negativer errno on error
3987 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003988static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003989{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003990 struct hdd_ipa_priv *hdd_ipa;
3991
3992 if (wlan_hdd_validate_context(hdd_ctx))
3993 return 0;
3994
3995 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003996
3997 if (!hdd_ipa_is_enabled(hdd_ctx))
3998 return 0;
3999
4000 /*
4001 * Check if IPA is ready for suspend, If we are here means, there is
4002 * high chance that suspend would go through but just to avoid any race
4003 * condition after suspend started, these checks are conducted before
4004 * allowing to suspend.
4005 */
4006 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4007 return -EAGAIN;
4008
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304009 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004010
4011 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304012 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004013 return -EAGAIN;
4014 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304015 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004016
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304017 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004018 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304019 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004020
4021 return 0;
4022}
4023
4024/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004025 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4026 * @hdd_ctx: Global HDD context
4027 *
4028 * Return: 0 on success, negativer errno on error
4029 */
4030int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4031{
4032 int ret;
4033
4034 cds_ssr_protect(__func__);
4035 ret = __hdd_ipa_suspend(hdd_ctx);
4036 cds_ssr_unprotect(__func__);
4037
4038 return ret;
4039}
4040
4041/**
4042 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004043 * hdd_ctx: Global HDD context
4044 *
4045 * Return: 0 on success, negative errno on error
4046 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004047static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004048{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004049 struct hdd_ipa_priv *hdd_ipa;
4050
4051 if (wlan_hdd_validate_context(hdd_ctx))
4052 return 0;
4053
4054 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004055
4056 if (!hdd_ipa_is_enabled(hdd_ctx))
4057 return 0;
4058
4059 schedule_work(&hdd_ipa->pm_work);
4060
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304061 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004062 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304063 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004064
4065 return 0;
4066}
4067
4068/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004069 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4070 * hdd_ctx: Global HDD context
4071 *
4072 * Return: 0 on success, negative errno on error
4073 */
4074int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4075{
4076 int ret;
4077
4078 cds_ssr_protect(__func__);
4079 ret = __hdd_ipa_resume(hdd_ctx);
4080 cds_ssr_unprotect(__func__);
4081
4082 return ret;
4083}
4084
4085/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004086 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4087 * @hdd_ipa: Global HDD IPA context
4088 *
4089 * Return: 0 on success, negative errno on error
4090 */
4091static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4092{
4093 int i, ret = 0;
4094 struct ipa_sys_connect_params *ipa;
4095 uint32_t desc_fifo_sz;
4096
4097 /* The maximum number of descriptors that can be provided to a BAM at
4098 * once is one less than the total number of descriptors that the buffer
4099 * can contain.
4100 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4101 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4102 * be provided at once.
4103 * Because of above requirement, one extra descriptor will be added to
4104 * make sure hardware always has one descriptor.
4105 */
4106 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4107 + sizeof(struct sps_iovec);
4108
4109 /*setup TX pipes */
4110 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4111 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4112
4113 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4114 ipa->desc_fifo_sz = desc_fifo_sz;
4115 ipa->priv = &hdd_ipa->iface_context[i];
4116 ipa->notify = hdd_ipa_i2w_cb;
4117
4118 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4119 ipa->ipa_ep_cfg.hdr.hdr_len =
4120 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4121 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4122 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4123 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4124 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4125 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4126 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4127 } else {
4128 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4129 }
4130 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4131
4132 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4133 ipa->keep_ipa_awake = 1;
4134
4135 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4136 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304137 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004138 " ret: %d", i, ret);
4139 goto setup_sys_pipe_fail;
4140 }
4141 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4142 }
4143
4144 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4145 /*
4146 * Hard code it here, this can be extended if in case
4147 * PROD pipe is also per interface.
4148 * Right now there is no advantage of doing this.
4149 */
4150 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4151
4152 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4153
4154 ipa->client = hdd_ipa->prod_client;
4155
4156 ipa->desc_fifo_sz = desc_fifo_sz;
4157 ipa->priv = hdd_ipa;
4158 ipa->notify = hdd_ipa_w2i_cb;
4159
4160 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4161 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4162 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4163 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4164
4165 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4166 ipa->keep_ipa_awake = 1;
4167
4168 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4169 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304170 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004171 "Failed for RX pipe: %d", ret);
4172 goto setup_sys_pipe_fail;
4173 }
4174 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4175 }
4176
4177 return ret;
4178
4179setup_sys_pipe_fail:
4180
4181 while (--i >= 0) {
4182 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304183 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004184 sizeof(struct hdd_ipa_sys_pipe));
4185 }
4186
4187 return ret;
4188}
4189
4190/**
4191 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4192 * @hdd_ipa: Global HDD IPA context
4193 *
4194 * Return: None
4195 */
4196static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4197{
4198 int ret = 0, i;
4199 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4200 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4201 ret =
4202 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4203 conn_hdl);
4204 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304205 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004206 ret);
4207
4208 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4209 }
4210 }
4211}
4212
4213/**
4214 * hdd_ipa_register_interface() - register IPA interface
4215 * @hdd_ipa: Global IPA context
4216 * @iface_context: Per-interface IPA context
4217 *
4218 * Return: 0 on success, negative errno on error
4219 */
4220static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
4221 struct hdd_ipa_iface_context
4222 *iface_context)
4223{
4224 struct ipa_tx_intf tx_intf;
4225 struct ipa_rx_intf rx_intf;
4226 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
4227 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
4228 char *ifname = iface_context->adapter->dev->name;
4229
4230 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
4231 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
4232
4233 int num_prop = 1;
4234 int ret = 0;
4235
4236 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
4237 num_prop++;
4238
4239 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
4240 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304241 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004242 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304243 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004244 goto register_interface_fail;
4245 }
4246
4247 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
4248 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304249 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004250 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304251 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004252 goto register_interface_fail;
4253 }
4254
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304255 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
4256 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257
4258 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4259 ifname, HDD_IPA_IPV4_NAME_EXT);
4260 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4261 ifname, HDD_IPA_IPV6_NAME_EXT);
4262
4263 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4264 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
4265 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4266 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4267
4268 /*
4269 * Interface ID is 3rd byte in the CLD header. Add the meta data and
4270 * mask to identify the interface in IPA hardware
4271 */
4272 rx_prop[IPA_IP_v4].attrib.meta_data =
4273 htonl(iface_context->adapter->sessionId << 16);
4274 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4275
4276 rx_intf.num_props++;
4277 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4278 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4279 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
4280 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4281 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4282 rx_prop[IPA_IP_v4].attrib.meta_data =
4283 htonl(iface_context->adapter->sessionId << 16);
4284 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4285
4286 rx_intf.num_props++;
4287 }
4288
4289 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4290 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4291 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4292 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
4293 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
4294 IPA_RESOURCE_NAME_MAX);
4295 tx_intf.num_props++;
4296
4297 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4298 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4299 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4300 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4301 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
4302 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
4303 IPA_RESOURCE_NAME_MAX);
4304 tx_intf.num_props++;
4305 }
4306
4307 tx_intf.prop = tx_prop;
4308 rx_intf.prop = rx_prop;
4309
4310 /* Call the ipa api to register interface */
4311 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
4312
4313register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304314 qdf_mem_free(tx_prop);
4315 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004316 return ret;
4317}
4318
4319/**
4320 * hdd_remove_ipa_header() - Remove a specific header from IPA
4321 * @name: Name of the header to be removed
4322 *
4323 * Return: None
4324 */
4325static void hdd_ipa_remove_header(char *name)
4326{
4327 struct ipa_ioc_get_hdr hdrlookup;
4328 int ret = 0, len;
4329 struct ipa_ioc_del_hdr *ipa_hdr;
4330
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304331 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004332 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
4333 ret = ipa_get_hdr(&hdrlookup);
4334 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304335 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 name, ret);
4337 return;
4338 }
4339
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304340 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004341 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304342 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004343 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304344 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004345 return;
4346 }
4347 ipa_hdr->num_hdls = 1;
4348 ipa_hdr->commit = 0;
4349 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
4350 ipa_hdr->hdl[0].status = -1;
4351 ret = ipa_del_hdr(ipa_hdr);
4352 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304353 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004354 ret);
4355
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304356 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004357}
4358
4359/**
Yun Parkb187d542016-11-14 18:10:04 -08004360 * wlan_ipa_add_hdr() - Add IPA Tx header
4361 * @ipa_hdr: pointer to IPA header addition parameters
4362 *
4363 * Call IPA API to add IPA Tx header descriptor
4364 * and dump Tx header struct
4365 *
4366 * Return: 0 for success, non-zero for failure
4367 */
4368static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
4369{
4370 int ret;
4371
4372 hdd_info("==== IPA Tx Header ====\n"
4373 "name: %s\n"
4374 "hdr_len: %d\n"
4375 "type: %d\n"
4376 "is_partial: %d\n"
4377 "hdr_hdl: 0x%x\n"
4378 "status: %d\n"
4379 "is_eth2_ofst_valid: %d\n"
4380 "eth2_ofst: %d\n",
4381 ipa_hdr->hdr[0].name,
4382 ipa_hdr->hdr[0].hdr_len,
4383 ipa_hdr->hdr[0].type,
4384 ipa_hdr->hdr[0].is_partial,
4385 ipa_hdr->hdr[0].hdr_hdl,
4386 ipa_hdr->hdr[0].status,
4387 ipa_hdr->hdr[0].is_eth2_ofst_valid,
4388 ipa_hdr->hdr[0].eth2_ofst);
4389
4390 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:",
4391 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4392
4393 ret = ipa_add_hdr(ipa_hdr);
4394 return ret;
4395}
4396
4397/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004398 * hdd_ipa_add_header_info() - Add IPA header for a given interface
4399 * @hdd_ipa: Global HDD IPA context
4400 * @iface_context: Interface-specific HDD IPA context
4401 * @mac_addr: Interface MAC address
4402 *
4403 * Return: 0 on success, negativer errno value on error
4404 */
4405static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
4406 struct hdd_ipa_iface_context *iface_context,
4407 uint8_t *mac_addr)
4408{
4409 hdd_adapter_t *adapter = iface_context->adapter;
4410 char *ifname;
4411 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
4412 int ret = -EINVAL;
4413 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
4414 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
4415
4416 ifname = adapter->dev->name;
4417
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304418 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004419 ifname, mac_addr);
4420
4421 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304422 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423 + sizeof(struct ipa_hdr_add));
4424 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304425 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004426 "%s: ipa_hdr allocation failed", ifname);
4427 ret = -ENOMEM;
4428 goto end;
4429 }
4430
4431 ipa_hdr->commit = 0;
4432 ipa_hdr->num_hdrs = 1;
4433
4434 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4435 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4436 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4437 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4438 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304439 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004440 "ifname=%s, vdev_id=%d",
4441 ifname, uc_tx_hdr->ipa_hd.vdev_id);
4442 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4443 ifname, HDD_IPA_IPV4_NAME_EXT);
4444 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
4445 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
4446 ipa_hdr->hdr[0].is_partial = 1;
4447 ipa_hdr->hdr[0].hdr_hdl = 0;
4448 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4449 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4450
Yun Parkb187d542016-11-14 18:10:04 -08004451 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004452 } else {
4453 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4454
4455 /* Set the Source MAC */
4456 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
4457 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4458
4459 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4460 ifname, HDD_IPA_IPV4_NAME_EXT);
4461 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4462 ipa_hdr->hdr[0].is_partial = 1;
4463 ipa_hdr->hdr[0].hdr_hdl = 0;
4464 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4465 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4466
4467 /* Set the type to IPV4 in the header */
4468 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
4469
4470 ret = ipa_add_hdr(ipa_hdr);
4471 }
4472 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304473 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004474 ifname, ret);
4475 goto end;
4476 }
4477
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304478 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004479 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4480
4481 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4482 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4483 ifname, HDD_IPA_IPV6_NAME_EXT);
4484
4485 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4486 uc_tx_hdr =
4487 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4488 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004489 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004490 } else {
4491 /* Set the type to IPV6 in the header */
4492 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4493 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004494 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004495 }
4496
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004497 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304498 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004499 "%s: IPv6 add hdr failed: %d", ifname, ret);
4500 goto clean_ipv4_hdr;
4501 }
4502
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304503 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004504 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4505 }
4506
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304507 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004508
4509 return ret;
4510
4511clean_ipv4_hdr:
4512 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4513 ifname, HDD_IPA_IPV4_NAME_EXT);
4514 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
4515end:
4516 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304517 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004518
4519 return ret;
4520}
4521
4522/**
4523 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
4524 * @adapter: Adapter upon which IPA was previously configured
4525 *
4526 * Return: None
4527 */
4528static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
4529{
4530 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4531 int ret;
4532 char name_ipa[IPA_RESOURCE_NAME_MAX];
4533
4534 /* Remove the headers */
4535 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4536 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
4537 hdd_ipa_remove_header(name_ipa);
4538
4539 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4540 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4541 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
4542 hdd_ipa_remove_header(name_ipa);
4543 }
4544 /* unregister the interface with IPA */
4545 ret = ipa_deregister_intf(adapter->dev->name);
4546 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304547 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004548 "%s: ipa_deregister_intf fail: %d",
4549 adapter->dev->name, ret);
4550}
4551
4552/**
4553 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4554 * @iface_context: interface-specific IPA context
4555 *
4556 * Return: None
4557 */
4558static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4559{
4560 if (iface_context == NULL)
4561 return;
4562
4563 hdd_ipa_clean_hdr(iface_context->adapter);
4564
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304565 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004566 iface_context->adapter->ipa_context = NULL;
4567 iface_context->adapter = NULL;
4568 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304569 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004570 iface_context->ifa_address = 0;
4571 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304572 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004573 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304574 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004575 }
4576 iface_context->hdd_ipa->num_iface--;
4577}
4578
4579/**
4580 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4581 * @hdd_ipa: HDD IPA global context
4582 * @adapter: Interface upon which IPA is being setup
4583 * @sta_id: Station ID of the API instance
4584 *
4585 * Return: 0 on success, negative errno value on error
4586 */
4587static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
4588 hdd_adapter_t *adapter, uint8_t sta_id)
4589{
4590 struct hdd_ipa_iface_context *iface_context = NULL;
4591 void *tl_context = NULL;
4592 int i, ret = 0;
4593
4594 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4595 * channel change indication. Since these indications are sent by lower
4596 * layer as SAP updates and IPA doesn't have to do anything for these
4597 * updates so ignoring!
4598 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004599 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004600 return 0;
4601
4602 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4603 if (hdd_ipa->iface_context[i].adapter == NULL) {
4604 iface_context = &(hdd_ipa->iface_context[i]);
4605 break;
4606 }
4607 }
4608
4609 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304610 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004611 "All the IPA interfaces are in use");
4612 ret = -ENOMEM;
4613 goto end;
4614 }
4615
4616 adapter->ipa_context = iface_context;
4617 iface_context->adapter = adapter;
4618 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004619 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07004620 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004621 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304622 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623 "Not able to get TL context sta_id: %d", sta_id);
4624 ret = -EINVAL;
4625 goto end;
4626 }
4627
4628 iface_context->tl_context = tl_context;
4629
4630 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
4631 adapter->dev->dev_addr);
4632
4633 if (ret)
4634 goto end;
4635
4636 /* Configure the TX and RX pipes filter rules */
4637 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
4638 if (ret)
4639 goto cleanup_header;
4640
4641 hdd_ipa->num_iface++;
4642 return ret;
4643
4644cleanup_header:
4645
4646 hdd_ipa_clean_hdr(adapter);
4647end:
4648 if (iface_context)
4649 hdd_ipa_cleanup_iface(iface_context);
4650 return ret;
4651}
4652
Yun Parka27049a2016-10-11 12:30:49 -07004653#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004654/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004655 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004656 * @mcc_mode: 0=MCC/1=SCC
4657 *
4658 * Return: 0 on success, negative errno value on error
4659 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004660static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004661{
4662 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304663 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004664 hdd_adapter_t *pAdapter;
4665 struct ipa_msg_meta meta;
4666 struct ipa_wlan_msg *msg;
4667 int ret;
4668
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004669 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004670 return -EINVAL;
4671
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004672 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4673 return -EINVAL;
4674
4675 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004676 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004677 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304678 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004679 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08004680 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004681 pAdapter->device_mode == QDF_SAP_MODE) {
4682 hdd_info("MCC->SCC: Flush TxRx queue(d_mode=%d)",
4683 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004684 hdd_deinit_tx_rx(pAdapter);
4685 }
4686 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004687 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004688 adapter_node = next;
4689 }
4690 }
4691
4692 /* Send SCC/MCC Switching event to IPA */
4693 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304694 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004695 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004696 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004697 return -ENOMEM;
4698 }
4699
4700 meta.msg_type = mcc_mode ?
4701 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004702 hdd_info("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004703
4704 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4705
4706 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004707 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004708 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304709 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004710 }
4711
4712 return ret;
4713}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004714
4715/**
4716 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4717 * @mcc_mode: 0=MCC/1=SCC
4718 *
4719 * Return: 0 on success, negative errno value on error
4720 */
4721int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
4722{
4723 int ret;
4724
4725 cds_ssr_protect(__func__);
4726 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4727 cds_ssr_unprotect(__func__);
4728
4729 return ret;
4730}
Yun Parka27049a2016-10-11 12:30:49 -07004731#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004732
4733/**
4734 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4735 * @event: IPA WLAN event to be converted to a string
4736 *
4737 * Return: ASCII string representing the IPA WLAN event
4738 */
4739static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4740{
4741 switch (event) {
4742 case WLAN_CLIENT_CONNECT:
4743 return "WLAN_CLIENT_CONNECT";
4744 case WLAN_CLIENT_DISCONNECT:
4745 return "WLAN_CLIENT_DISCONNECT";
4746 case WLAN_CLIENT_POWER_SAVE_MODE:
4747 return "WLAN_CLIENT_POWER_SAVE_MODE";
4748 case WLAN_CLIENT_NORMAL_MODE:
4749 return "WLAN_CLIENT_NORMAL_MODE";
4750 case SW_ROUTING_ENABLE:
4751 return "SW_ROUTING_ENABLE";
4752 case SW_ROUTING_DISABLE:
4753 return "SW_ROUTING_DISABLE";
4754 case WLAN_AP_CONNECT:
4755 return "WLAN_AP_CONNECT";
4756 case WLAN_AP_DISCONNECT:
4757 return "WLAN_AP_DISCONNECT";
4758 case WLAN_STA_CONNECT:
4759 return "WLAN_STA_CONNECT";
4760 case WLAN_STA_DISCONNECT:
4761 return "WLAN_STA_DISCONNECT";
4762 case WLAN_CLIENT_CONNECT_EX:
4763 return "WLAN_CLIENT_CONNECT_EX";
4764
4765 case IPA_WLAN_EVENT_MAX:
4766 default:
4767 return "UNKNOWN";
4768 }
4769}
4770
4771/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004772 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4773 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4774 *
4775 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4776 */
4777static enum ipa_wlan_event
4778hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4779{
4780 enum ipa_wlan_event ipa_event;
4781
4782 switch (hdd_ipa_event_type) {
4783 case HDD_IPA_CLIENT_CONNECT:
4784 ipa_event = WLAN_CLIENT_CONNECT;
4785 break;
4786 case HDD_IPA_CLIENT_DISCONNECT:
4787 ipa_event = WLAN_CLIENT_DISCONNECT;
4788 break;
4789 case HDD_IPA_AP_CONNECT:
4790 ipa_event = WLAN_AP_CONNECT;
4791 break;
4792 case HDD_IPA_AP_DISCONNECT:
4793 ipa_event = WLAN_AP_DISCONNECT;
4794 break;
4795 case HDD_IPA_STA_CONNECT:
4796 ipa_event = WLAN_STA_CONNECT;
4797 break;
4798 case HDD_IPA_STA_DISCONNECT:
4799 ipa_event = WLAN_STA_DISCONNECT;
4800 break;
4801 case HDD_IPA_CLIENT_CONNECT_EX:
4802 ipa_event = WLAN_CLIENT_CONNECT_EX;
4803 break;
4804 case HDD_IPA_WLAN_EVENT_MAX:
4805 default:
4806 ipa_event = IPA_WLAN_EVENT_MAX;
4807 break;
4808 }
4809 return ipa_event;
4810
4811}
4812
4813/**
4814 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004815 * @adapter: adapter upon which the event was received
4816 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004817 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004818 * @mac_address: MAC address associated with the event
4819 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004820 * This function is meant to be called from within wlan_hdd_ipa.c
4821 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004822 * Return: 0 on success, negative errno value on error
4823 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07004824static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004825 enum ipa_wlan_event type, uint8_t *mac_addr)
4826{
4827 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4828 struct ipa_msg_meta meta;
4829 struct ipa_wlan_msg *msg;
4830 struct ipa_wlan_msg_ex *msg_ex = NULL;
4831 int ret;
4832
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304833 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004834 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
4835 mac_addr, sta_id);
4836
4837 if (type >= IPA_WLAN_EVENT_MAX)
4838 return -EINVAL;
4839
4840 if (WARN_ON(is_zero_ether_addr(mac_addr)))
4841 return -EINVAL;
4842
4843 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304844 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004845 return -EINVAL;
4846 }
4847
4848 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
4849 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08004850 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004851 return 0;
4852 }
4853
4854 /*
4855 * During IPA UC resource loading/unloading new events can be issued.
4856 * Store the events separately and handle them later.
4857 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004858 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4859 if (hdd_ipa->resource_loading) {
4860 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004861 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08004862
Yun Park7c4f31b2016-11-30 10:09:21 -08004863 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA resource %s inprogress",
4864 hdd_ipa->resource_loading ? "load":"unload");
4865
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004866 hdd_err("IPA resource %s inprogress",
4867 hdd_ipa->resource_loading ? "load":"unload");
Yun Parkf19e07d2015-11-20 11:34:27 -08004868
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004869 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004870
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004871 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4872 if (pending_event_count >= HDD_IPA_MAX_PENDING_EVENT_COUNT) {
4873 hdd_notice("Reached max pending event count");
4874 qdf_list_remove_front(&hdd_ipa->pending_event,
4875 (qdf_list_node_t **)&pending_event);
4876 } else {
4877 pending_event =
4878 (struct ipa_uc_pending_event *)qdf_mem_malloc(
4879 sizeof(struct ipa_uc_pending_event));
4880 }
4881
4882 if (!pending_event) {
Yun Park7c4f31b2016-11-30 10:09:21 -08004883 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4884 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004885 qdf_mutex_release(&hdd_ipa->event_lock);
4886 return -ENOMEM;
4887 }
4888
4889 pending_event->adapter = adapter;
4890 pending_event->sta_id = sta_id;
4891 pending_event->type = type;
4892 qdf_mem_copy(pending_event->mac_addr,
4893 mac_addr,
4894 QDF_MAC_ADDR_SIZE);
4895 qdf_list_insert_back(&hdd_ipa->pending_event,
4896 &pending_event->node);
4897
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304898 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004899 return 0;
4900 } else if (hdd_ipa->resource_unloading) {
4901 hdd_err("%s: IPA resource unload inprogress", __func__);
4902 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004903 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004904 }
4905
4906 hdd_ipa->stats.event[type]++;
4907
Leo Chang3bc8fed2015-11-13 10:59:47 -08004908 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004909 switch (type) {
4910 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004911 qdf_mutex_acquire(&hdd_ipa->event_lock);
4912
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004913 /* STA already connected and without disconnect, connect again
4914 * This is Roaming scenario
4915 */
4916 if (hdd_ipa->sta_connected)
4917 hdd_ipa_cleanup_iface(adapter->ipa_context);
4918
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004919 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4920 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304921 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004922 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004923 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004924
Yun Park8f289c82016-10-18 16:38:21 -07004925 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4926 (hdd_ipa->sap_num_connected_sta > 0) &&
4927 !hdd_ipa->sta_connected) {
4928 qdf_mutex_release(&hdd_ipa->event_lock);
4929 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004930 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004931 qdf_mutex_acquire(&hdd_ipa->event_lock);
4932 }
4933
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004934 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004935 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004936 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004937
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004938 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07004939
4940 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004941 break;
4942
4943 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004944 qdf_mutex_acquire(&hdd_ipa->event_lock);
4945
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004946 /* For DFS channel we get two start_bss event (before and after
4947 * CAC). Also when ACS range includes both DFS and non DFS
4948 * channels, we could possibly change channel many times due to
4949 * RADAR detection and chosen channel may not be a DFS channels.
4950 * So dont return error here. Just discard the event.
4951 */
Yun Park8f289c82016-10-18 16:38:21 -07004952 if (adapter->ipa_context) {
4953 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004954 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07004955 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004956
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004957 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4958 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004959 hdd_err("%s: Evt: %d, Interface setup failed",
4960 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304961 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004962 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004963 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004964
Yun Park8f289c82016-10-18 16:38:21 -07004965 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4966 qdf_mutex_release(&hdd_ipa->event_lock);
4967 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004968 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004969 qdf_mutex_acquire(&hdd_ipa->event_lock);
4970 }
4971
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004972 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004973 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004974 (adapter->ipa_context))->iface_id;
4975
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304976 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004977 break;
4978
4979 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304980 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004981
4982 if (!hdd_ipa->sta_connected) {
Yun Parkb187d542016-11-14 18:10:04 -08004983 hdd_err("%s: Evt: %d, STA already disconnected",
4984 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304985 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004986 return -EINVAL;
4987 }
Yun Parka37592b2016-06-11 17:10:28 -07004988
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004989 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07004990
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004991 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08004992 hdd_notice("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004993 msg_ex->name);
4994 } else {
4995 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07004996 if (!hdd_ipa->num_iface &&
4997 (HDD_IPA_UC_NUM_WDI_PIPE ==
4998 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005000 }
5001
Yun Park74127cf2016-09-18 11:22:41 -07005002 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5003 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005004 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005005 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005006 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005007 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005008 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5009 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005010 }
5011
Yun Park8f289c82016-10-18 16:38:21 -07005012 hdd_ipa_cleanup_iface(adapter->ipa_context);
5013
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305014 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005015 break;
5016
5017 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005018 qdf_mutex_acquire(&hdd_ipa->event_lock);
5019
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005020 if (!adapter->ipa_context) {
Yun Parkb187d542016-11-14 18:10:04 -08005021 hdd_err("%s: Evt: %d, SAP already disconnected",
5022 msg_ex->name, meta.msg_type);
Yun Park8f289c82016-10-18 16:38:21 -07005023 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005024 return -EINVAL;
5025 }
5026
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005027 if ((!hdd_ipa->num_iface) &&
5028 (HDD_IPA_UC_NUM_WDI_PIPE ==
5029 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005030 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005031 /*
5032 * We disable WDI pipes directly here since
5033 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5034 * processed when unloading WLAN driver is in
5035 * progress
5036 */
5037 hdd_ipa_uc_disable_pipes(hdd_ipa);
5038 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305039 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005040 "NO INTF left but still pipe clean up");
5041 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5042 }
5043 }
5044
5045 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005046 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005047 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005048 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005049 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005050 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5051 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005052 }
Yun Parka37592b2016-06-11 17:10:28 -07005053
Yun Park8f289c82016-10-18 16:38:21 -07005054 hdd_ipa_cleanup_iface(adapter->ipa_context);
5055
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305056 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005057 break;
5058
5059 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005060 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305061 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005062 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305063 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005064 return 0;
5065 }
5066
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305067 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005068 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5069 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005070 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305071 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005072 "%s: STA ID %d found, not valid",
5073 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005074 return 0;
5075 }
Yun Park312f71a2015-12-08 10:22:42 -08005076
5077 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005078 if (hdd_ipa->sap_num_connected_sta == 0 &&
5079 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005080 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005081 hdd_ipa->sta_connected) {
5082 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005083 hdd_ipa_uc_offload_enable_disable(
5084 hdd_get_adapter(hdd_ipa->hdd_ctx,
5085 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005086 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005087 qdf_mutex_acquire(&hdd_ipa->event_lock);
5088 }
Yun Parka37592b2016-06-11 17:10:28 -07005089
Yun Park312f71a2015-12-08 10:22:42 -08005090 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5091 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305092 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005093 "%s: handle 1st con ret %d",
5094 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005095
5096 if (hdd_ipa_uc_sta_is_enabled(
5097 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005098 hdd_ipa->sta_connected) {
5099 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005100 hdd_ipa_uc_offload_enable_disable(
5101 hdd_get_adapter(
5102 hdd_ipa->hdd_ctx,
5103 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005104 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005105 } else {
5106 qdf_mutex_release(&hdd_ipa->event_lock);
5107 }
Yun Parka37592b2016-06-11 17:10:28 -07005108
Yun Park312f71a2015-12-08 10:22:42 -08005109 return ret;
5110 }
5111 }
5112
5113 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005114
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305115 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005116
5117 meta.msg_type = type;
5118 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5119 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305120 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005121
5122 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305123 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005124 "msg_ex allocation failed");
5125 return -ENOMEM;
5126 }
5127 strlcpy(msg_ex->name, adapter->dev->name,
5128 IPA_RESOURCE_NAME_MAX);
5129 msg_ex->num_of_attribs = 1;
5130 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5131 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5132 msg_ex->attribs[0].offset =
5133 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5134 } else {
5135 msg_ex->attribs[0].offset =
5136 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5137 }
5138 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5139 IPA_MAC_ADDR_SIZE);
5140
5141 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5142
5143 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305144 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305145 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305146 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005147 return ret;
5148 }
5149 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005150 return ret;
5151
5152 case WLAN_CLIENT_DISCONNECT:
5153 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305154 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005155 "%s: IPA UC OFFLOAD NOT ENABLED",
5156 msg_ex->name);
5157 return 0;
5158 }
5159
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305160 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005161 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305162 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005163 "%s: STA ID %d NOT found, not valid",
5164 msg_ex->name, sta_id);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305165 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005166 return 0;
5167 }
5168 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005169
Yun Park9b5030f2016-11-08 12:02:37 -08005170 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005171 if (!hdd_ipa->sap_num_connected_sta &&
5172 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005173 if ((false == hdd_ipa->resource_unloading)
5174 && (HDD_IPA_UC_NUM_WDI_PIPE ==
5175 hdd_ipa->activated_fw_pipe)) {
5176 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5177 }
5178
Yun Park8f289c82016-10-18 16:38:21 -07005179 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005180
5181 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5182 hdd_ipa->sta_connected)
5183 hdd_ipa_uc_offload_enable_disable(
5184 hdd_get_adapter(hdd_ipa->hdd_ctx,
5185 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005186 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005187 } else {
5188 qdf_mutex_release(&hdd_ipa->event_lock);
5189 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005190 break;
5191
5192 default:
5193 return 0;
5194 }
5195
5196 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305197 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005198 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305199 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005200 return -ENOMEM;
5201 }
5202
5203 meta.msg_type = type;
5204 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5205 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5206
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305207 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005208 msg->name, meta.msg_type);
5209
5210 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5211
5212 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005213 hdd_err("%s: Evt: %d fail:%d",
5214 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305215 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005216 return ret;
5217 }
5218
5219 hdd_ipa->stats.num_send_msg++;
5220
5221end:
5222 return ret;
5223}
5224
5225/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005226 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005227 * @adapter: adapter upon which the event was received
5228 * @sta_id: station id for the event
5229 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5230 * @mac_address: MAC address associated with the event
5231 *
5232 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5233 *
5234 * Return: 0 on success, negative errno value on error
5235 */
5236int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
5237 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5238{
5239 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005240 int ret = 0;
5241
5242 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005243
Leo Changa202b522016-10-14 16:13:50 -07005244 /* Data path offload only support for STA and SAP mode */
5245 if ((QDF_STA_MODE == adapter->device_mode) ||
5246 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005247 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005248
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005249 cds_ssr_unprotect(__func__);
5250
5251 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005252}
5253
5254/**
5255 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5256 * @hdd_ipa: Global HDD IPA context
5257 *
5258 * Return: None
5259 */
5260static void
5261hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5262{
5263 unsigned int pending_event_count;
5264 struct ipa_uc_pending_event *pending_event = NULL;
5265
5266 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
5267 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
5268 "%s, Pending Event Count %d", __func__, pending_event_count);
5269 if (!pending_event_count) {
5270 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
5271 "%s, No Pending Event", __func__);
5272 return;
5273 }
5274
5275 qdf_list_remove_front(&hdd_ipa->pending_event,
5276 (qdf_list_node_t **)&pending_event);
5277 while (pending_event != NULL) {
5278 __hdd_ipa_wlan_evt(pending_event->adapter,
5279 pending_event->type,
5280 pending_event->sta_id,
5281 pending_event->mac_addr);
5282 qdf_mem_free(pending_event);
5283 pending_event = NULL;
5284 qdf_list_remove_front(&hdd_ipa->pending_event,
5285 (qdf_list_node_t **)&pending_event);
5286 }
5287}
5288
5289/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005290 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5291 * @state: IPA RM state value
5292 *
5293 * Return: ASCII string representing the IPA RM state
5294 */
5295static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5296{
5297 switch (state) {
5298 case HDD_IPA_RM_RELEASED:
5299 return "RELEASED";
5300 case HDD_IPA_RM_GRANT_PENDING:
5301 return "GRANT_PENDING";
5302 case HDD_IPA_RM_GRANTED:
5303 return "GRANTED";
5304 }
5305
5306 return "UNKNOWN";
5307}
5308
5309/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005310 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005311 * @hdd_ctx: HDD global context
5312 *
5313 * Allocate hdd_ipa resources, ipa pipe resource and register
5314 * wlan interface with IPA module.
5315 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305316 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005317 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005318static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005319{
5320 struct hdd_ipa_priv *hdd_ipa = NULL;
5321 int ret, i;
5322 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005323 struct ol_txrx_pdev_t *pdev = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005324
5325 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305326 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005327
Yun Parkbaa62862017-01-18 13:43:34 -08005328 ENTER();
5329
5330 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005331 if (!pdev) {
5332 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5333 goto fail_return;
5334 }
5335
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305336 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005337 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305338 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005339 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005340 }
5341
5342 hdd_ctx->hdd_ipa = hdd_ipa;
5343 ghdd_ipa = hdd_ipa;
5344 hdd_ipa->hdd_ctx = hdd_ctx;
5345 hdd_ipa->num_iface = 0;
5346
5347 /* Create the interface context */
5348 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5349 iface_context = &hdd_ipa->iface_context[i];
5350 iface_context->hdd_ipa = hdd_ipa;
5351 iface_context->cons_client =
5352 hdd_ipa_adapter_2_client[i].cons_client;
5353 iface_context->prod_client =
5354 hdd_ipa_adapter_2_client[i].prod_client;
5355 iface_context->iface_id = i;
5356 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305357 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005358 }
5359 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005360 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5361 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005362 }
5363
Leo Chang69c39692016-10-12 20:11:12 -07005364 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305365 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305366 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005367
5368 ret = hdd_ipa_setup_rm(hdd_ipa);
5369 if (ret)
5370 goto fail_setup_rm;
5371
5372 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5373 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305374 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005375 hdd_ipa->sap_num_connected_sta = 0;
5376 hdd_ipa->ipa_tx_packets_diff = 0;
5377 hdd_ipa->ipa_rx_packets_diff = 0;
5378 hdd_ipa->ipa_p_tx_packets = 0;
5379 hdd_ipa->ipa_p_rx_packets = 0;
5380 hdd_ipa->resource_loading = false;
5381 hdd_ipa->resource_unloading = false;
5382 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005383 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08005384 hdd_ipa->wdi_enabled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005385 /* Setup IPA sys_pipe for MCC */
5386 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5387 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5388 if (ret)
5389 goto fail_create_sys_pipe;
5390 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005391 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5392 goto fail_create_sys_pipe;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005393 } else {
5394 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5395 if (ret)
5396 goto fail_create_sys_pipe;
5397 }
5398
Yun Parkbaa62862017-01-18 13:43:34 -08005399 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305400 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005401
5402fail_create_sys_pipe:
5403 hdd_ipa_destroy_rm_resource(hdd_ipa);
5404fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305405 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305406 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005407 hdd_ctx->hdd_ipa = NULL;
5408 ghdd_ipa = NULL;
5409fail_return:
Yun Parkbaa62862017-01-18 13:43:34 -08005410 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305411 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005412}
5413
5414/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005415 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5416 * @hdd_ctx: HDD global context
5417 *
5418 * Allocate hdd_ipa resources, ipa pipe resource and register
5419 * wlan interface with IPA module.
5420 *
5421 * Return: QDF_STATUS enumeration
5422 */
5423QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
5424{
5425 QDF_STATUS ret;
5426
5427 cds_ssr_protect(__func__);
5428 ret = __hdd_ipa_init(hdd_ctx);
5429 cds_ssr_unprotect(__func__);
5430
5431 return ret;
5432}
5433
Arun Khandavallicc544b32017-01-30 19:52:16 +05305434
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005435/**
Yun Parkf19e07d2015-11-20 11:34:27 -08005436 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
5437 * @hdd_ipa: pointer to HDD IPA struct
5438 *
5439 * Return: none
5440 */
Jeff Johnsond7720632016-10-05 16:04:32 -07005441static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08005442{
5443 struct ipa_uc_pending_event *pending_event = NULL;
5444
Anurag Chouhanffb21542016-02-17 14:33:03 +05305445 while (qdf_list_remove_front(&hdd_ipa->pending_event,
5446 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305447 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005448 }
5449
Anurag Chouhanffb21542016-02-17 14:33:03 +05305450 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005451}
5452
5453/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005454 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005455 * @hdd_ctx: HDD global context
5456 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305457 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005458 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005459static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005460{
5461 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5462 int i;
5463 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305464 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005465 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5466
5467 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305468 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005469
5470 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5471 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5472 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5473 }
5474
5475 /* Teardown IPA sys_pipe for MCC */
5476 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5477 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5478
5479 hdd_ipa_destroy_rm_resource(hdd_ipa);
5480
5481#ifdef WLAN_OPEN_SOURCE
5482 cancel_work_sync(&hdd_ipa->pm_work);
5483#endif
5484
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305485 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005486
Nirav Shahcbc6d722016-03-01 16:24:53 +05305487 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5488 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305489 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005490
5491 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
5492 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
5493
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305494 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005495 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305496 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005497
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305498 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005499
5500 /* destory the interface lock */
5501 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5502 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305503 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005504 }
5505
5506 /* This should never hit but still make sure that there are no pending
5507 * descriptor in IPA hardware
5508 */
5509 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305510 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005511 "IPA Pending write done: %d Waiting!",
5512 hdd_ipa->pending_hw_desc_cnt);
5513
5514 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
5515 usleep_range(100, 100);
5516 }
5517
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305518 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005519 "IPA Pending write done: desc: %d %s(%d)!",
5520 hdd_ipa->pending_hw_desc_cnt,
5521 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
5522 : "leak", i);
5523 }
5524 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08005525 if (ipa_uc_dereg_rdyCB())
5526 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5527 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005528 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005529 if (true == hdd_ipa->uc_loaded) {
5530 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305531 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
5532 __func__, hdd_ipa->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005533 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
5534 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305535 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
5536 __func__, hdd_ipa->rx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005537 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
5538 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305539 qdf_mutex_destroy(&hdd_ipa->event_lock);
5540 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005541 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005542
5543#ifdef WLAN_OPEN_SOURCE
5544 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5545 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5546 hdd_ipa->uc_op_work[i].msg = NULL;
5547 }
5548#endif
5549 }
5550
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305551 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005552 hdd_ctx->hdd_ipa = NULL;
5553
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305554 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005555}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005556
5557/**
5558 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5559 * @hdd_ctx: HDD global context
5560 *
5561 * Return: QDF_STATUS enumeration
5562 */
5563QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
5564{
5565 QDF_STATUS ret;
5566
5567 cds_ssr_protect(__func__);
5568 ret = __hdd_ipa_cleanup(hdd_ctx);
5569 cds_ssr_unprotect(__func__);
5570
5571 return ret;
5572}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005573#endif /* IPA_OFFLOAD */