blob: 2557ad54025251c18ea691e749e940ad6a2f0625 [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;
Anurag Chouhan210db072016-02-22 18:42:15 +0530447 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530448 qdf_mutex_t rt_debug_lock;
449 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800450 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800451 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530452 qdf_dma_addr_t tx_comp_doorbell_paddr;
453 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800454
455 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
456 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800457};
458
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800459/**
Houston Hoffman23e76f92016-02-26 12:19:11 -0800460 * FIXME: The following conversion routines are just stubs.
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800461 * They will be implemented fully by another update.
462 * The stubs will let the compile go ahead, and functionality
463 * is broken.
464 * This should be OK and IPA is not enabled yet
465 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700466static void *wlan_hdd_stub_priv_to_addr(uint32_t priv)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800467{
468 void *vaddr;
469 uint32_t ipa_priv = priv;
470
471 vaddr = &ipa_priv; /* just to use the var */
472 vaddr = NULL;
473 return vaddr;
474}
475
Jeff Johnsond7720632016-10-05 16:04:32 -0700476static uint32_t wlan_hdd_stub_addr_to_priv(void *ptr)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800477{
478 uint32_t ipa_priv = 0;
479
480 BUG_ON(ptr == NULL);
481 return ipa_priv;
482}
Leo Changcc923e22016-06-16 15:29:03 -0700483
484#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
485#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800486#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
487#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
488#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
489#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
490#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
491#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700492#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
493 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800494
495#define HDD_IPA_GET_IFACE_ID(_data) \
496 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
497
498#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530499 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800500 "%s:%d: "fmt, __func__, __LINE__, ## args)
501
Govind Singhb6a89772016-08-12 11:23:35 +0530502#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
503 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
504 "%s:%d: "fmt, __func__, __LINE__, ## args)
505
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800506#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
507 do { \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530508 QDF_TRACE(QDF_MODULE_ID_HDD, _lvl, "%s:", _prefix); \
509 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800510 } while (0)
511
512#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
513 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
514
515#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
516 do { \
517 hdd_ipa->ipa_rx_internel_drop_count++; \
518 } while (0)
519#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
520 do { \
521 hdd_ipa->ipa_rx_net_send_count++; \
522 } while (0)
523#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
524
Leo Chang07b28f62016-05-11 12:29:22 -0700525#if defined (QCA_WIFI_3_0) && defined (CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800526#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
527do { \
528 pipe_in.u.ul.rdy_ring_rp_va = \
529 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
530 pipe_in.u.ul.rdy_comp_ring_base_pa = \
531 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
532 pipe_in.u.ul.rdy_comp_ring_size = \
533 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
534 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
535 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
536 pipe_in.u.ul.rdy_comp_ring_wp_va = \
537 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800538} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700539
540#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800541#else
542/* Do nothing */
543#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
Leo Chang63d73612016-10-18 18:09:43 -0700544#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700545#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800546
Yun Parkb187d542016-11-14 18:10:04 -0800547#define HDD_IPA_DBG_DUMP_RX_LEN 32
548#define HDD_IPA_DBG_DUMP_TX_LEN 48
549
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550static struct hdd_ipa_adapter_2_client {
551 enum ipa_client_type cons_client;
552 enum ipa_client_type prod_client;
553} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
554 {
555 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
556 }, {
557 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
558 }, {
559 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
560 },
561};
562
563/* For Tx pipes, use Ethernet-II Header format */
564struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
565 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800566 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800567 0x00000000,
568 0x00000000
569 },
570 {
571 0x00000000
572 },
573 {
574 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
575 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
576 0x0008
577 }
578};
579
580/* For Tx pipes, use 802.3 Header format */
581static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
582 {
583 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
584 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
585 0x00 /* length can be zero */
586 },
587 {
588 /* LLC SNAP header 8 bytes */
589 0xaa, 0xaa,
590 {0x03, 0x00, 0x00, 0x00},
591 0x0008 /* type value(2 bytes) ,filled by wlan */
592 /* 0x0800 - IPV4, 0x86dd - IPV6 */
593 }
594};
595
596static const char *op_string[] = {
597 "TX_SUSPEND",
598 "TX_RESUME",
599 "RX_SUSPEND",
600 "RX_RESUME",
601 "STATS",
602};
603
604static struct hdd_ipa_priv *ghdd_ipa;
605
606/* Local Function Prototypes */
607static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
608 unsigned long data);
609static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
610 unsigned long data);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800611static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800612
613static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Mohit Khannafa99aea2016-05-12 21:43:13 -0700614static void hdd_ipa_uc_proc_pending_event (struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800615
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800616#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
617 defined(IPA_CLIENT_IS_MHI_CONS))
618/**
619 * hdd_ipa_uc_get_db_paddr() - Get Doorbell physical address
620 * @db_paddr: Doorbell physical address should be given bu IPA
621 * @client: IPA client type
622 *
623 * Query doorbell physical address from IPA
624 * IPA will give physical address for TX COMP and RX READY
625 *
626 * Return: None
627 */
628static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
629 enum ipa_client_type client)
630{
631 struct ipa_wdi_db_params dbpa;
632
633 dbpa.client = client;
634 ipa_uc_wdi_get_dbpa(&dbpa);
635 *db_paddr = dbpa.uc_door_bell_pa;
636 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s PROD DB get dbpa 0x%x",
637 __func__, (unsigned int)dbpa.uc_door_bell_pa);
638}
639
640/**
641 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
642 * @priv_ctxt: hdd ipa local context
643 *
644 * Will be called by IPA context.
645 * It's atomic context, then should be scheduled to kworker thread
646 *
647 * Return: None
648 */
649static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
650{
651 struct hdd_ipa_priv *hdd_ipa;
652 struct op_msg_type *msg;
653 struct uc_op_work_struct *uc_op_work;
654
655 if (priv_ctxt == NULL) {
656 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
657 return;
658 }
659
660 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
661 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
662 if (!msg) {
663 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
664 return;
665 }
666
667 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
668
669 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
670
671 /* When the same uC OPCODE is already pended, just return */
672 if (uc_op_work->msg)
673 return;
674
675 uc_op_work->msg = msg;
676 schedule_work(&uc_op_work->work);
677}
678
679/**
680 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
681 * @hdd_ipa: HDD IPA local context
682 *
683 * Register IPA UC ready callback function to IPA kernel driver
684 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
685 * open WDI pipe after WLAN driver loading finished
686 *
687 * Return: 0 Success
688 * -EPERM Registration fail
689 */
690static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
691{
692 struct ipa_wdi_uc_ready_params uc_ready_param;
693
694 hdd_ipa->uc_loaded = false;
695 uc_ready_param.priv = (void *)hdd_ipa;
696 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
697 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
698 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
699 "UC Ready CB register fail");
700 return -EPERM;
701 }
702 if (true == uc_ready_param.is_uC_ready) {
703 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "UC Ready");
704 hdd_ipa->uc_loaded = true;
705 }
706
707 return 0;
708}
709
710#ifdef QCA_LL_TX_FLOW_CONTROL_V2
711static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
712{
713 return 0;
714}
715#else
716/**
717 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
718 * @ctrl: WDI control value
719 *
720 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
721 *
722 * Return: 0 on message send to ipa, -1 on failure
723 */
724static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
725{
726 struct ipa_msg_meta meta;
727 struct ipa_wlan_msg *ipa_msg;
728 int ret = 0;
729
730 /* WDI enable message to IPA */
731 meta.msg_len = sizeof(*ipa_msg);
732 ipa_msg = qdf_mem_malloc(meta.msg_len);
733 if (ipa_msg == NULL) {
734 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
735 "msg allocation failed");
736 return -ENOMEM;
737 }
738
739 if (ctrl == true)
740 meta.msg_type = WLAN_WDI_ENABLE;
741 else
742 meta.msg_type = WLAN_WDI_DISABLE;
743
744 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
745 "ipa_send_msg(Evt:%d)", meta.msg_type);
746 ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
747 if (ret) {
748 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
749 "ipa_send_msg(Evt:%d)-fail=%d",
750 meta.msg_type, ret);
751 qdf_mem_free(ipa_msg);
752 }
753 return 0;
754}
755#endif /* QCA_LL_TX_FLOW_CONTROL_V2 */
756
757#else
758static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr,
759 enum ipa_client_type client)
760{
761 /* Do nothing */
762}
763
764static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
765{
766 hdd_ipa->uc_loaded = true;
767 return 0;
768}
769
770static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
771{
772 return 0;
773}
774#endif
775
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800776/**
777 * hdd_ipa_is_enabled() - Is IPA enabled?
778 * @hdd_ctx: Global HDD context
779 *
780 * Return: true if IPA is enabled, false otherwise
781 */
782bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
783{
784 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
785}
786
787/**
788 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
789 * @hdd_ctx: Global HDD context
790 *
791 * Return: true if IPA uC offload is enabled, false otherwise
792 */
793bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
794{
795 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
796}
797
798/**
799 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
800 * @hdd_ctx: Global HDD context
801 *
802 * Return: true if STA mode IPA uC offload is enabled, false otherwise
803 */
804static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
805{
806 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
807}
808
809/**
Guolei Bianca144d82016-11-10 11:07:42 +0800810 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
811 * @hdd_ipa: Global HDD IPA context
812 *
813 * Return: None
814 */
815#ifdef IPA_UC_STA_OFFLOAD
816static inline void hdd_ipa_uc_sta_reset_sta_connected(
817 struct hdd_ipa_priv *hdd_ipa)
818{
819 vos_lock_acquire(&hdd_ipa->event_lock);
820 hdd_ipa->sta_connected = 0;
821 vos_lock_release(&hdd_ipa->event_lock);
822}
823#else
824static inline void hdd_ipa_uc_sta_reset_sta_connected(
825 struct hdd_ipa_priv *hdd_ipa)
826{
827}
828#endif
829
830/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800831 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
832 * @hdd_ipa: Global HDD IPA context
833 *
834 * Return: true if pre-filter is enabled, otherwise false
835 */
836static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
837{
838 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
839 HDD_IPA_PRE_FILTER_ENABLE_MASK);
840}
841
842/**
843 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
844 * @hdd_ipa: Global HDD IPA context
845 *
846 * Return: true if IPv6 is enabled, otherwise false
847 */
848static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
849{
850 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
851}
852
853/**
854 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
855 * @hdd_ipa: Global HDD IPA context
856 *
857 * Return: true if resource manager is enabled, otherwise false
858 */
859static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
860{
861 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
862}
863
864/**
865 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
866 * @hdd_ipa: Global HDD IPA context
867 *
868 * Return: true if resource manager is enabled, otherwise false
869 */
870static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
871{
872 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
873}
874
875/**
876 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
877 * @hdd_ipa: Global HDD IPA context
878 *
879 * Return: true if clock scaling is enabled, otherwise false
880 */
881static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
882{
883 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
884 HDD_IPA_CLK_SCALING_ENABLE_MASK |
885 HDD_IPA_RM_ENABLE_MASK);
886}
887
888/**
889 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
890 * @ctext: pointer to hdd context.
891 *
892 * If rt debug enabled, periodically called, and fill debug buffer
893 *
894 * Return: none
895 */
896static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
897{
898 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
899 struct hdd_ipa_priv *hdd_ipa;
900 struct uc_rt_debug_info *dump_info = NULL;
901
902 if (wlan_hdd_validate_context(hdd_ctx))
903 return;
904
905 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530906 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800907 "%s: IPA UC is not enabled", __func__);
908 return;
909 }
910
911 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
912
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530913 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800914 dump_info = &hdd_ipa->rt_bug_buffer[
915 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
916
Deepthi Gowri6acee342016-10-28 15:00:38 +0530917 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800918 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
919 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
920 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800921 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800922 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
923 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
925 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530926 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800927
Anurag Chouhan210db072016-02-22 18:42:15 +0530928 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
930}
931
932/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700933 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934 * @hdd_ctx: pointer to hdd context.
935 *
936 * If rt debug enabled, dump debug buffer contents based on requirement
937 *
938 * Return: none
939 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700940static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941{
942 struct hdd_ipa_priv *hdd_ipa;
943 unsigned int dump_count;
944 unsigned int dump_index;
945 struct uc_rt_debug_info *dump_info = NULL;
946
947 if (wlan_hdd_validate_context(hdd_ctx))
948 return;
949
950 hdd_ipa = hdd_ctx->hdd_ipa;
951 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530952 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800953 "%s: IPA UC is not enabled", __func__);
954 return;
955 }
956
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530957 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800958 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530959 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb187d542016-11-14 18:10:04 -0800960 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800961
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530962 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800963 for (dump_count = 0;
964 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
965 dump_count++) {
966 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
967 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
968 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530969 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530970 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800971 dump_info->time, dump_info->ipa_excep_count,
972 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800973 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800974 dump_info->rx_destructor_call,
975 dump_info->rx_discard_count);
976 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530977 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530978 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800979 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
980}
981
982/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700983 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
984 * __hdd_ipa_uc_rt_debug_host_dump
985 * @hdd_ctx: pointer to hdd context.
986 *
987 * If rt debug enabled, dump debug buffer contents based on requirement
988 *
989 * Return: none
990 */
991void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
992{
993 cds_ssr_protect(__func__);
994 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
995 cds_ssr_unprotect(__func__);
996}
997
998/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800999 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
1000 * @ctext: pointer to hdd context.
1001 *
1002 * periodically called by timer expire
1003 * will try to alloc dummy memory and detect out of memory condition
1004 * if out of memory detected, dump wlan-ipa stats
1005 *
1006 * Return: none
1007 */
1008static void hdd_ipa_uc_rt_debug_handler(void *ctext)
1009{
1010 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001011 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001012 void *dummy_ptr = NULL;
1013
1014 if (wlan_hdd_validate_context(hdd_ctx))
1015 return;
1016
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001017 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1018
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08001020 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001021 return;
1022 }
1023
1024 /* Allocate dummy buffer periodically and free immediately. this will
1025 * proactively detect OOM and if allocation fails dump ipa stats
1026 */
1027 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
1028 GFP_KERNEL | GFP_ATOMIC);
1029 if (!dummy_ptr) {
Yun Parkb187d542016-11-14 18:10:04 -08001030 hdd_alert("Dummy alloc fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001031 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1032 hdd_ipa_uc_stat_request(
Krunal Sonibe766b02016-03-10 13:00:44 -08001033 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034 } else {
1035 kfree(dummy_ptr);
1036 }
1037
Anurag Chouhan210db072016-02-22 18:42:15 +05301038 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 HDD_IPA_UC_RT_DEBUG_PERIOD);
1040}
1041
1042/**
Yun Parkb187d542016-11-14 18:10:04 -08001043 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044 * @skb: packet pinter
1045 *
1046 * when free data packet, will be invoked by wlan client and will increase
1047 * free counter
1048 *
1049 * Return: none
1050 */
Jeff Johnsond7720632016-10-05 16:04:32 -07001051static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052{
1053 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301054 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001055 "%s: invalid hdd context", __func__);
1056 return;
1057 }
1058
1059 ghdd_ipa->ipa_rx_destructor_count++;
1060}
1061
1062/**
Yun Parkb187d542016-11-14 18:10:04 -08001063 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001064 * @hdd_ctx: hdd main context
1065 *
1066 * free all rt debugging resources
1067 *
1068 * Return: none
1069 */
1070static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
1071{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001072 struct hdd_ipa_priv *hdd_ipa;
1073
1074 if (wlan_hdd_validate_context(hdd_ctx))
1075 return;
1076
1077 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001078
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301079 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001080
1081 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08001082 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001083 return;
1084 }
1085
Anurag Chouhan210db072016-02-22 18:42:15 +05301086 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001087 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1088 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1089 }
1090 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1091
1092 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301093 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1094 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001095 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301096 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001097}
1098
1099/**
Yun Parkb187d542016-11-14 18:10:04 -08001100 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001101 * @hdd_ctx: hdd main context
1102 *
1103 * alloc and initialize all rt debugging resources
1104 *
1105 * Return: none
1106 */
1107static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
1108{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001109 struct hdd_ipa_priv *hdd_ipa;
1110
1111 if (wlan_hdd_validate_context(hdd_ctx))
1112 return;
1113
1114 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001115
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301116 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301118 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001119 sizeof(struct uc_rt_debug_info) *
1120 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1121 hdd_ipa->ipa_tx_forward = 0;
1122 hdd_ipa->ipa_rx_discard = 0;
1123 hdd_ipa->ipa_rx_net_send_count = 0;
1124 hdd_ipa->ipa_rx_internel_drop_count = 0;
1125 hdd_ipa->ipa_rx_destructor_count = 0;
1126
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001127 /* Reatime debug enable on feature enable */
1128 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08001129 hdd_notice("IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130 return;
1131 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001132
1133 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1134 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1135 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1136 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1137
Anurag Chouhan210db072016-02-22 18:42:15 +05301138 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001139 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301140 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001141 HDD_IPA_UC_RT_DEBUG_PERIOD);
1142
1143}
1144
1145/**
Yun Parkb187d542016-11-14 18:10:04 -08001146 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1147 * @hdd_ipa: HDD IPA struct
1148 *
1149 * Dump entries in struct hdd_ipa
1150 *
1151 * Return: none
1152 */
1153static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1154{
1155 int i;
1156
1157 /* HDD IPA */
1158 hdd_err("==== HDD IPA ====\n"
1159 "num_iface: %d\n"
1160 "rm_state: %d\n"
1161 "rm_lock: %p\n"
1162 "uc_rm_work: %p\n"
1163 "uc_op_work: %p\n"
1164 "wake_lock: %p\n"
1165 "wake_lock_work: %p\n"
1166 "wake_lock_released: %d\n"
1167 "prod_client: %d\n"
1168 "tx_ref_cnt: %d\n"
1169 "pm_queue_head----\n"
1170 "\thead: %p\n"
1171 "\ttail: %p\n"
1172 "\tqlen: %d\n"
1173 "pm_work: %p\n"
1174 "pm_lock: %p\n"
1175 "suspended: %d\n",
1176 hdd_ipa->num_iface,
1177 hdd_ipa->rm_state,
1178 &hdd_ipa->rm_lock,
1179 &hdd_ipa->uc_rm_work,
1180 &hdd_ipa->uc_op_work,
1181 &hdd_ipa->wake_lock,
1182 &hdd_ipa->wake_lock_work,
1183 hdd_ipa->wake_lock_released,
1184 hdd_ipa->prod_client,
1185 hdd_ipa->tx_ref_cnt.counter,
1186 hdd_ipa->pm_queue_head.head,
1187 hdd_ipa->pm_queue_head.tail,
1188 hdd_ipa->pm_queue_head.qlen,
1189 &hdd_ipa->pm_work,
1190 &hdd_ipa->pm_lock,
1191 hdd_ipa->suspended);
1192 hdd_err("\npending_hw_desc_cnt: %d\n"
1193 "hw_desc_cnt: %d\n"
1194 "q_lock: %p\n"
1195 "freeq_cnt: %d\n"
1196 "free_desc_head----\n"
1197 "\tnext: %p\n"
1198 "\tprev: %p\n"
1199 "pend_q_cnt: %d\n"
1200 "pend_desc_head----\n"
1201 "\tnext: %p\n"
1202 "\tprev: %p\n"
1203 "hdd_ctx: %p\n"
1204 "debugfs_dir: %p\n"
1205 "stats: %p\n"
1206 "ipv4_notifier: %p\n"
1207 "curr_prod_bw: %d\n"
1208 "curr_cons_bw: %d\n"
1209 "activated_fw_pipe: %d\n"
1210 "sap_num_connected_sta: %d\n"
1211 "sta_connected: %d\n",
1212 hdd_ipa->pending_hw_desc_cnt,
1213 hdd_ipa->hw_desc_cnt,
1214 &hdd_ipa->q_lock,
1215 hdd_ipa->freeq_cnt,
1216 hdd_ipa->free_desc_head.next,
1217 hdd_ipa->free_desc_head.prev,
1218 hdd_ipa->pend_q_cnt,
1219 hdd_ipa->pend_desc_head.next,
1220 hdd_ipa->pend_desc_head.prev,
1221 hdd_ipa->hdd_ctx,
1222 hdd_ipa->debugfs_dir,
1223 &hdd_ipa->stats,
1224 &hdd_ipa->ipv4_notifier,
1225 hdd_ipa->curr_prod_bw,
1226 hdd_ipa->curr_cons_bw,
1227 hdd_ipa->activated_fw_pipe,
1228 hdd_ipa->sap_num_connected_sta,
1229 (unsigned int)hdd_ipa->sta_connected
1230 );
1231 hdd_err("\ntx_pipe_handle: 0x%x\n"
1232 "rx_pipe_handle: 0x%x\n"
1233 "resource_loading: %d\n"
1234 "resource_unloading: %d\n"
1235 "pending_cons_req: %d\n"
1236 "pending_event----\n"
1237 "\tanchor.next: %p\n"
1238 "\tanchor.prev: %p\n"
1239 "\tcount: %d\n"
1240 "\tmax_size: %d\n"
1241 "event_lock: %p\n"
1242 "ipa_tx_packets_diff: %d\n"
1243 "ipa_rx_packets_diff: %d\n"
1244 "ipa_p_tx_packets: %d\n"
1245 "ipa_p_rx_packets: %d\n"
1246 "stat_req_reason: %d\n",
1247 hdd_ipa->tx_pipe_handle,
1248 hdd_ipa->rx_pipe_handle,
1249 hdd_ipa->resource_loading,
1250 hdd_ipa->resource_unloading,
1251 hdd_ipa->pending_cons_req,
1252 hdd_ipa->pending_event.anchor.next,
1253 hdd_ipa->pending_event.anchor.prev,
1254 hdd_ipa->pending_event.count,
1255 hdd_ipa->pending_event.max_size,
1256 &hdd_ipa->event_lock,
1257 hdd_ipa->ipa_tx_packets_diff,
1258 hdd_ipa->ipa_rx_packets_diff,
1259 hdd_ipa->ipa_p_tx_packets,
1260 hdd_ipa->ipa_p_rx_packets,
1261 hdd_ipa->stat_req_reason);
1262
1263 hdd_err("assoc_stas_map([id]is_reserved/sta_id): ");
1264 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
1265 hdd_err(" [%d]%d/%d", i,
1266 hdd_ipa->assoc_stas_map[i].is_reserved,
1267 hdd_ipa->assoc_stas_map[i].sta_id);
1268 }
1269}
1270
1271/**
1272 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1273 * @hdd_ipa: HDD IPA struct
1274 *
1275 * Dump entire struct hdd_ipa_sys_pipe
1276 *
1277 * Return: none
1278 */
1279static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1280{
1281 int i;
1282
1283 /* IPA SYS Pipes */
1284 hdd_err("==== IPA SYS Pipes ====\n");
1285
1286 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1287 struct hdd_ipa_sys_pipe *sys_pipe;
1288 struct ipa_sys_connect_params *ipa_sys_params;
1289
1290 sys_pipe = &hdd_ipa->sys_pipe[i];
1291 ipa_sys_params = &sys_pipe->ipa_sys_params;
1292
1293 hdd_err("sys_pipe[%d]----\n"
1294 "\tconn_hdl: 0x%x\n"
1295 "\tconn_hdl_valid: %d\n"
1296 "\tnat_en: %d\n"
1297 "\thdr_len %d\n"
1298 "\thdr_additional_const_len: %d\n"
1299 "\thdr_ofst_pkt_size_valid: %d\n"
1300 "\thdr_ofst_pkt_size: %d\n"
1301 "\thdr_little_endian: %d\n"
1302 "\tmode: %d\n"
1303 "\tclient: %d\n"
1304 "\tdesc_fifo_sz: %d\n"
1305 "\tpriv: %p\n"
1306 "\tnotify: %p\n"
1307 "\tskip_ep_cfg: %d\n"
1308 "\tkeep_ipa_awake: %d\n",
1309 i,
1310 sys_pipe->conn_hdl,
1311 sys_pipe->conn_hdl_valid,
1312 ipa_sys_params->ipa_ep_cfg.nat.nat_en,
1313 ipa_sys_params->ipa_ep_cfg.hdr.hdr_len,
1314 ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len,
1315 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid,
1316 ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size,
1317 ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian,
1318 ipa_sys_params->ipa_ep_cfg.mode.mode,
1319 ipa_sys_params->client,
1320 ipa_sys_params->desc_fifo_sz,
1321 ipa_sys_params->priv,
1322 ipa_sys_params->notify,
1323 ipa_sys_params->skip_ep_cfg,
1324 ipa_sys_params->keep_ipa_awake);
1325 }
1326}
1327
1328/**
1329 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1330 * @hdd_ipa: HDD IPA struct
1331 *
1332 * Dump entire struct hdd_ipa_iface_context
1333 *
1334 * Return: none
1335 */
1336static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1337{
1338 int i;
1339
1340 /* IPA Interface Contexts */
1341 hdd_err("==== IPA Interface Contexts ====\n");
1342
1343 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1344 struct hdd_ipa_iface_context *iface_context;
1345
1346 iface_context = &hdd_ipa->iface_context[i];
1347
1348 hdd_err("iface_context[%d]----\n"
1349 "\thdd_ipa: %p\n"
1350 "\tadapter: %p\n"
1351 "\ttl_context: %p\n"
1352 "\tcons_client: %d\n"
1353 "\tprod_client: %d\n"
1354 "\tiface_id: %d\n"
1355 "\tsta_id: %d\n"
1356 "\tinterface_lock: %p\n"
1357 "\tifa_address: 0x%x\n",
1358 i,
1359 iface_context->hdd_ipa,
1360 iface_context->adapter,
1361 iface_context->tl_context,
1362 iface_context->cons_client,
1363 iface_context->prod_client,
1364 iface_context->iface_id,
1365 iface_context->sta_id,
1366 &iface_context->interface_lock,
1367 iface_context->ifa_address);
1368 }
1369}
1370
1371/**
1372 * hdd_ipa_dump_info() - dump HDD IPA struct
1373 * @pHddCtx: hdd main context
1374 *
1375 * Dump entire struct hdd_ipa
1376 *
1377 * Return: none
1378 */
1379void hdd_ipa_dump_info(hdd_context_t *hdd_ctx)
1380{
1381 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1382
1383 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1384 hdd_ipa_dump_sys_pipe(hdd_ipa);
1385 hdd_ipa_dump_iface_context(hdd_ipa);
1386}
1387
1388/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001389 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001390 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001391 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1392 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001393 *
1394 * Return: true if IPA is enabled, false otherwise
1395 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001396static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001397 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1398{
1399 struct hdd_ipa_priv *hdd_ipa;
1400
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401 *ipa_tx_diff = 0;
1402 *ipa_rx_diff = 0;
1403
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001404 if (wlan_hdd_validate_context(hdd_ctx))
1405 return;
1406
1407 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1408
1409 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1410 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411 return;
1412 }
1413
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301414 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1416 (false == hdd_ipa->resource_loading)) {
1417 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1418 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkb187d542016-11-14 18:10:04 -08001419 hdd_debug("STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001420 *ipa_tx_diff, *ipa_rx_diff);
1421 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301422 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001423 return;
1424}
1425
1426/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001427 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1428 * @hdd_ctx: Global HDD context
1429 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1430 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1431 *
1432 * Return: true if IPA is enabled, false otherwise
1433 */
1434void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1435 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1436{
1437 cds_ssr_protect(__func__);
1438 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1439 cds_ssr_unprotect(__func__);
1440}
1441
1442/**
1443 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001444 * @adapter: network adapter
1445 * @reason: STAT REQ Reason
1446 *
1447 * Return: None
1448 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001449static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001450{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001451 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001452 struct hdd_ipa_priv *hdd_ipa;
1453
1454 if (!adapter) {
1455 return;
1456 }
1457
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001458 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1459
1460 if (wlan_hdd_validate_context(hdd_ctx))
1461 return;
1462
1463 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1464 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1465 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001466 return;
1467 }
1468
Yun Parkb187d542016-11-14 18:10:04 -08001469 hdd_debug("STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301470 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001471 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1472 (false == hdd_ipa->resource_loading)) {
1473 hdd_ipa->stat_req_reason = reason;
1474 wma_cli_set_command(
1475 (int)adapter->sessionId,
1476 (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
1477 0, VDEV_CMD);
1478 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301479 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001480}
1481
1482/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001483 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1484 * @adapter: network adapter
1485 * @reason: STAT REQ Reason
1486 *
1487 * Return: None
1488 */
1489void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1490{
1491 cds_ssr_protect(__func__);
1492 __hdd_ipa_uc_stat_request(adapter, reason);
1493 cds_ssr_unprotect(__func__);
1494}
1495
1496/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001497 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1498 * @hdd_ipa: Global HDD IPA context
1499 * @sta_add: Should station be added
1500 * @sta_id: ID of the station being queried
1501 *
1502 * Return: true if the station was found
1503 */
1504static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1505 bool sta_add, uint8_t sta_id)
1506{
1507 bool sta_found = false;
1508 uint8_t idx;
1509 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1510 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1511 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1512 sta_found = true;
1513 break;
1514 }
1515 }
1516 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301517 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001518 "%s: STA ID %d already exist, cannot add",
1519 __func__, sta_id);
1520 return sta_found;
1521 }
1522 if (sta_add) {
1523 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1524 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1525 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1526 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1527 return sta_found;
1528 }
1529 }
1530 }
1531 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301532 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001533 "%s: STA ID %d does not exist, cannot delete",
1534 __func__, sta_id);
1535 return sta_found;
1536 }
1537 if (!sta_add) {
1538 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1539 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1540 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1541 hdd_ipa->assoc_stas_map[idx].is_reserved =
1542 false;
1543 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1544 return sta_found;
1545 }
1546 }
1547 }
1548 return sta_found;
1549}
1550
1551/**
1552 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1553 * @hdd_ipa: Global HDD IPA context
1554 *
1555 * Return: 0 on success, negative errno if error
1556 */
1557static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1558{
1559 int result;
1560 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001561 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001562
1563 /* ACTIVATE TX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301564 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001565 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1566 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001567 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1568 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301569 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001570 "%s: Enable TX PIPE fail, code %d",
1571 __func__, result);
1572 return result;
1573 }
1574 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1575 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301576 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001577 "%s: Resume TX PIPE fail, code %d",
1578 __func__, result);
1579 return result;
1580 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001581 cdp_ipa_set_active(soc,
1582 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1583 true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001584
1585 /* ACTIVATE RX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301586 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001587 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1588 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001589 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1590 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301591 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001592 "%s: Enable RX PIPE fail, code %d",
1593 __func__, result);
1594 return result;
1595 }
1596 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1597 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301598 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001599 "%s: Resume RX PIPE fail, code %d",
1600 __func__, result);
1601 return result;
1602 }
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001603 cdp_ipa_set_active(soc,
1604 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1605 true, false);
Leo Change3e49442015-10-26 20:07:13 -07001606 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001607 return 0;
1608}
1609
1610/**
1611 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1612 * @hdd_ipa: Global HDD IPA context
1613 *
1614 * Return: 0 on success, negative errno if error
1615 */
1616static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1617{
1618 int result;
1619
Leo Change3e49442015-10-26 20:07:13 -07001620 hdd_ipa->ipa_pipes_down = true;
1621
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301622 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001623 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
1624 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301625 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626 "%s: Suspend RX PIPE fail, code %d",
1627 __func__, result);
1628 return result;
1629 }
1630 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1631 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301632 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001633 "%s: Disable RX PIPE fail, code %d",
1634 __func__, result);
1635 return result;
1636 }
1637
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301638 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001639 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
1640 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301641 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001642 "%s: Suspend TX PIPE fail, code %d",
1643 __func__, result);
1644 return result;
1645 }
1646 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1647 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301648 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001649 "%s: Disable TX PIPE fail, code %d",
1650 __func__, result);
1651 return result;
1652 }
1653
1654 return 0;
1655}
1656
1657/**
1658 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1659 * @hdd_ipa: Global HDD IPA context
1660 *
1661 * Return: 0 on success, negative errno if error
1662 */
1663static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1664{
1665 hdd_ipa->activated_fw_pipe = 0;
1666 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001667
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668 /* If RM feature enabled
1669 * Request PROD Resource first
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08001670 * PROD resource may return sync or async manners
1671 */
Yun Park4cab6ee2015-10-27 11:43:40 -07001672 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
1673 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1674 /* RM PROD request sync return
1675 * enable pipe immediately
1676 */
1677 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",
1680 __func__);
1681 hdd_ipa->resource_loading = false;
1682 return -EBUSY;
1683 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001684 }
1685 } else {
1686 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001687 * Just enabled all the PIPEs
1688 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301690 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001691 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692 __func__);
1693 hdd_ipa->resource_loading = false;
1694 return -EBUSY;
1695 }
1696 hdd_ipa->resource_loading = false;
1697 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001698
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301699 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001700 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701 return 0;
1702}
1703
1704/**
1705 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1706 * @hdd_ipa: Global HDD IPA context
1707 *
1708 * Return: None
1709 */
1710static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1711{
1712 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001713 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001714
Yun Park7c4f31b2016-11-30 10:09:21 -08001715 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
1716 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
1717 QDF_ASSERT(0);
1718 return;
1719 }
1720
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721 hdd_ipa->resource_unloading = true;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301722 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW RX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001723 cdp_ipa_set_active(soc,
1724 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1725 false, false);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301726 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW TX PIPE", __func__);
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08001727 cdp_ipa_set_active(soc,
1728 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
1729 false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730}
1731
1732/**
1733 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
1734 * @context: User context registered with TL (the IPA Global context is
1735 * registered
1736 * @rxpkt: Packet containing the notification
1737 * @staid: ID of the station associated with the packet
1738 *
1739 * Return: None
1740 */
1741static void
1742hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
1743{
1744 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301745 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001746
1747 /*
1748 * When SSR is going on or driver is unloading, just return.
1749 */
1750 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301751 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753
1754 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1755 return;
1756
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301757 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758 __func__, event);
1759
1760 switch (event) {
1761 case IPA_RM_RESOURCE_GRANTED:
1762 /* Differed RM Granted */
1763 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301764 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001765 if ((false == hdd_ipa->resource_unloading) &&
1766 (!hdd_ipa->activated_fw_pipe)) {
1767 hdd_ipa_uc_enable_pipes(hdd_ipa);
1768 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301769 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770 break;
1771
1772 case IPA_RM_RESOURCE_RELEASED:
1773 /* Differed RM Released */
1774 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775 break;
1776
1777 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301778 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779 "%s, invalid event code %d", __func__, event);
1780 break;
1781 }
1782}
1783
1784/**
1785 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
1786 * @hdd_ipa: Global HDD IPA context
1787 * @event: IPA resource manager event to be deferred
1788 *
1789 * This function is called when a resource manager event is received
1790 * from firmware in interrupt context. This function will defer the
1791 * handling to the OL RX thread
1792 *
1793 * Return: None
1794 */
1795static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
1796{
1797 enum ipa_rm_event event;
1798 struct uc_rm_work_struct *uc_rm_work = container_of(work,
1799 struct uc_rm_work_struct, work);
1800 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
1801 struct hdd_ipa_priv, uc_rm_work);
1802
1803 cds_ssr_protect(__func__);
1804 event = uc_rm_work->event;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301805 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806 "%s, posted event %d", __func__, event);
1807
1808 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
1809 cds_ssr_unprotect(__func__);
1810
1811 return;
1812}
1813
1814/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08001815 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
1816 * @ipa_ctxt: hdd ipa local context
1817 *
1818 * Will handle IPA UC image loaded indication comes from IPA kernel
1819 *
1820 * Return: None
1821 */
1822static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt)
1823{
1824 struct ipa_wdi_out_params pipe_out;
1825
1826 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__);
1827 if (true == ipa_ctxt->uc_loaded) {
1828 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s : UC already loaded",
1829 __func__);
1830 return;
1831 }
1832
1833 ipa_ctxt->uc_loaded = true;
1834 /* Connect pipe */
1835 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
1836 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
1837 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
1838 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1839 "%s : TX PIPE Handle %d, DBPA 0x%llx",
1840 __func__, ipa_ctxt->tx_pipe_handle,
1841 (unsigned long long) pipe_out.uc_door_bell_pa);
1842
1843 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
1844 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
1845 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
1846 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1847 "%s : RX PIPE Handle %d, DBPA 0x%llx",
1848 __func__, ipa_ctxt->rx_pipe_handle,
1849 (unsigned long long) pipe_out.uc_door_bell_pa);
1850
1851 /* If already any STA connected, enable IPA/FW PIPEs */
1852 if (ipa_ctxt->sap_num_connected_sta) {
1853 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
1854 "Client already connected, enable IPA/FW PIPEs");
1855 hdd_ipa_uc_handle_first_con(ipa_ctxt);
1856 }
1857}
1858
1859/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860 * hdd_ipa_uc_op_cb() - IPA uC operation callback
1861 * @op_msg: operation message received from firmware
1862 * @usr_ctxt: user context registered with TL (we register the HDD Global
1863 * context)
1864 *
1865 * Return: None
1866 */
1867static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
1868{
1869 struct op_msg_type *msg = op_msg;
1870 struct ipa_uc_fw_stats *uc_fw_stat;
1871 struct IpaHwStatsWDIInfoData_t ipa_stat;
1872 struct hdd_ipa_priv *hdd_ipa;
1873 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301874 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001875
1876 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301877 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878 return;
1879 }
1880
1881 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301882 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001883 "%s, INVALID OPCODE %d", __func__, msg->op_code);
1884 return;
1885 }
1886
1887 hdd_ctx = (hdd_context_t *) usr_ctxt;
1888
1889 /*
1890 * When SSR is going on or driver is unloading, just return.
1891 */
1892 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301893 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301894 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895 return;
1896 }
1897
1898 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1899
Govind Singhb6a89772016-08-12 11:23:35 +05301900 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001901 "%s, OPCODE %s", __func__, op_string[msg->op_code]);
1902
1903 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
1904 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301905 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001906 hdd_ipa->activated_fw_pipe++;
1907 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
1908 hdd_ipa->resource_loading = false;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08001909 if (hdd_ipa_uc_send_wdi_control_msg(true) < 0) {
1910 qdf_mutex_release(&hdd_ipa->event_lock);
1911 qdf_mem_free(op_msg);
1912 return;
1913 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001914 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08001915 if (hdd_ipa->pending_cons_req)
1916 ipa_rm_notify_completion(
1917 IPA_RM_RESOURCE_GRANTED,
1918 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08001919 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001920 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301921 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001922 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001923 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301924 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001925 hdd_ipa->activated_fw_pipe--;
1926 if (!hdd_ipa->activated_fw_pipe) {
1927 hdd_ipa_uc_disable_pipes(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08001928 if (hdd_ipa_uc_send_wdi_control_msg(false) < 0) {
1929 qdf_mutex_release(&hdd_ipa->event_lock);
1930 qdf_mem_free(op_msg);
1931 return;
1932 }
Yun Park5b635012015-12-02 15:05:01 -08001933 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1934 ipa_rm_release_resource(
1935 IPA_RM_RESOURCE_WLAN_PROD);
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08001936 /*
1937 * Sync return success from IPA
1938 * Enable/resume all the PIPEs
1939 */
Yun Park5b635012015-12-02 15:05:01 -08001940 hdd_ipa->resource_unloading = false;
1941 hdd_ipa_uc_proc_pending_event(hdd_ipa);
1942 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001943 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301944 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001945 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001947 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301949 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001951 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001952 "CE RING SIZE: %d\n"
1953 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001954 (unsigned long long)res->ce_sr_base_paddr,
1955 res->ce_sr_ring_size,
1956 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301957 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001959 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001960 "COMP RING SIZE: %d\n"
1961 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001962 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001963 (unsigned long long)res->tx_comp_ring_base_paddr,
1964 res->tx_comp_ring_size,
1965 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001966 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
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 RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001969 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001971 "IND RING DBELL : 0x%llx\n"
1972 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001973 "NUM EXCP PKT : %llu\n"
Yun Parkb187d542016-11-14 18:10:04 -08001974 "NUM TX FWD OK : %llu\n"
1975 "NUM TX FWD ERR : %llu",
Yun Park8b2bc4b2016-12-18 16:58:33 -08001976 (unsigned long long)res->rx_rdy_ring_base_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001977 res->rx_rdy_ring_size,
Yun Park8b2bc4b2016-12-18 16:58:33 -08001978 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
1979 (unsigned long long)res->rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001980 hdd_ipa->stats.num_rx_excep,
Yun Parkb187d542016-11-14 18:10:04 -08001981 hdd_ipa->stats.num_tx_fwd_ok,
1982 hdd_ipa->stats.num_tx_fwd_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301983 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984 "==== IPA_UC WLAN_HOST CONTROL ====\n"
1985 "SAP NUM STAs: %d\n"
1986 "STA CONNECTED: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001987 "CONCURRENT MODE: %s\n"
1988 "TX PIPE HDL: 0x%x\n"
1989 "RX PIPE HDL : 0x%x\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001990 "RSC LOADING : %d\n"
1991 "RSC UNLOADING : %d\n"
1992 "PNDNG CNS RQT : %d",
1993 hdd_ipa->sap_num_connected_sta,
1994 hdd_ipa->sta_connected,
Yun Parkb187d542016-11-14 18:10:04 -08001995 (hdd_ctx->mcc_mode ? "MCC" : "SCC"),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001996 hdd_ipa->tx_pipe_handle,
1997 hdd_ipa->rx_pipe_handle,
Yun Parkb187d542016-11-14 18:10:04 -08001998 hdd_ipa->resource_loading,
1999 hdd_ipa->resource_unloading,
2000 hdd_ipa->pending_cons_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002001
2002 /* STATs from FW */
2003 uc_fw_stat = (struct ipa_uc_fw_stats *)
2004 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302005 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 "==== IPA_UC WLAN_FW TX ====\n"
2007 "COMP RING BASE: 0x%x\n"
2008 "COMP RING SIZE: %d\n"
2009 "COMP RING DBELL : 0x%x\n"
2010 "COMP RING DBELL IND VAL : %d\n"
2011 "COMP RING DBELL CACHED VAL : %d\n"
2012 "COMP RING DBELL CACHED VAL : %d\n"
2013 "PKTS ENQ : %d\n"
2014 "PKTS COMP : %d\n"
2015 "IS SUSPEND : %d\n"
2016 "RSVD : 0x%x",
2017 uc_fw_stat->tx_comp_ring_base,
2018 uc_fw_stat->tx_comp_ring_size,
2019 uc_fw_stat->tx_comp_ring_dbell_addr,
2020 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2021 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2022 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2023 uc_fw_stat->tx_pkts_enqueued,
2024 uc_fw_stat->tx_pkts_completed,
Yun Parkb187d542016-11-14 18:10:04 -08002025 uc_fw_stat->tx_is_suspend,
2026 uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302027 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002028 "==== IPA_UC WLAN_FW RX ====\n"
2029 "IND RING BASE: 0x%x\n"
2030 "IND RING SIZE: %d\n"
2031 "IND RING DBELL : 0x%x\n"
2032 "IND RING DBELL IND VAL : %d\n"
2033 "IND RING DBELL CACHED VAL : %d\n"
2034 "RDY IND ADDR : 0x%x\n"
2035 "RDY IND CACHE VAL : %d\n"
2036 "RFIL IND : %d\n"
2037 "NUM PKT INDICAT : %d\n"
2038 "BUF REFIL : %d\n"
2039 "NUM DROP NO SPC : %d\n"
2040 "NUM DROP NO BUF : %d\n"
2041 "IS SUSPND : %d\n"
2042 "RSVD : 0x%x\n",
2043 uc_fw_stat->rx_ind_ring_base,
2044 uc_fw_stat->rx_ind_ring_size,
2045 uc_fw_stat->rx_ind_ring_dbell_addr,
2046 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2047 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2048 uc_fw_stat->rx_ind_ring_rdidx_addr,
2049 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2050 uc_fw_stat->rx_refill_idx,
2051 uc_fw_stat->rx_num_pkts_indicated,
2052 uc_fw_stat->rx_buf_refilled,
2053 uc_fw_stat->rx_num_ind_drop_no_space,
2054 uc_fw_stat->rx_num_ind_drop_no_buf,
Yun Parkb187d542016-11-14 18:10:04 -08002055 uc_fw_stat->rx_is_suspend,
2056 uc_fw_stat->rx_reserved);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002057 /* STATs from IPA */
2058 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302059 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002060 "==== IPA_UC IPA TX ====\n"
2061 "NUM PROCD : %d\n"
2062 "CE DBELL : 0x%x\n"
2063 "NUM DBELL FIRED : %d\n"
2064 "COMP RNG FULL : %d\n"
2065 "COMP RNG EMPT : %d\n"
2066 "COMP RNG USE HGH : %d\n"
2067 "COMP RNG USE LOW : %d\n"
2068 "BAM FIFO FULL : %d\n"
2069 "BAM FIFO EMPT : %d\n"
2070 "BAM FIFO USE HGH : %d\n"
2071 "BAM FIFO USE LOW : %d\n"
2072 "NUM DBELL : %d\n"
2073 "NUM UNEXP DBELL : %d\n"
2074 "NUM BAM INT HDL : 0x%x\n"
2075 "NUM BAM INT NON-RUN : 0x%x\n"
2076 "NUM QMB INT HDL : 0x%x",
2077 ipa_stat.tx_ch_stats.num_pkts_processed,
2078 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2079 ipa_stat.tx_ch_stats.num_db_fired,
2080 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2081 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2082 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2083 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2084 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2085 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2086 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2087 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2088 ipa_stat.tx_ch_stats.num_db,
2089 ipa_stat.tx_ch_stats.num_unexpected_db,
2090 ipa_stat.tx_ch_stats.num_bam_int_handled,
2091 ipa_stat.tx_ch_stats.
2092 num_bam_int_in_non_runnning_state,
2093 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2094
Anurag Chouhandf2b2682016-02-29 14:15:27 +05302095 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002096 "==== IPA_UC IPA RX ====\n"
2097 "MAX OST PKT : %d\n"
2098 "NUM PKT PRCSD : %d\n"
2099 "RNG RP : 0x%x\n"
2100 "COMP RNG FULL : %d\n"
2101 "COMP RNG EMPT : %d\n"
2102 "COMP RNG USE HGH : %d\n"
2103 "COMP RNG USE LOW : %d\n"
2104 "BAM FIFO FULL : %d\n"
2105 "BAM FIFO EMPT : %d\n"
2106 "BAM FIFO USE HGH : %d\n"
2107 "BAM FIFO USE LOW : %d\n"
2108 "NUM DB : %d\n"
2109 "NUM UNEXP DB : %d\n"
2110 "NUM BAM INT HNDL : 0x%x\n",
2111 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2112 ipa_stat.rx_ch_stats.num_pkts_processed,
2113 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2114 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2115 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2116 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2117 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2118 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2119 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2120 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2121 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2122 ipa_stat.rx_ch_stats.num_db,
2123 ipa_stat.rx_ch_stats.num_unexpected_db,
2124 ipa_stat.rx_ch_stats.num_bam_int_handled);
2125 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2126 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2127 /* STATs from FW */
2128 uc_fw_stat = (struct ipa_uc_fw_stats *)
2129 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302130 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002131 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2132 uc_fw_stat->tx_pkts_completed,
2133 hdd_ipa->ipa_p_tx_packets);
2134 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2135 (uc_fw_stat->rx_num_ind_drop_no_space +
2136 uc_fw_stat->rx_num_ind_drop_no_buf +
2137 uc_fw_stat->rx_num_pkts_indicated),
2138 hdd_ipa->ipa_p_rx_packets);
2139
2140 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2141 hdd_ipa->ipa_p_rx_packets =
2142 (uc_fw_stat->rx_num_ind_drop_no_space +
2143 uc_fw_stat->rx_num_ind_drop_no_buf +
2144 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302145 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002146 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2147 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2148 hdd_ipa_uc_loaded_handler(hdd_ipa);
2149 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002150 } else {
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002151 HDD_IPA_LOG(LOGE, "INVALID REASON %d",
2152 hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002153 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302154 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002155}
2156
2157
2158/**
2159 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2160 * @adapter: device adapter instance
2161 * @offload_type: MCC or SCC
2162 * @enable: TX offload enable or disable
2163 *
2164 * Return: none
2165 */
2166static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002167 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002168{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002169 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002170 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002171 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002172 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002173
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002174 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002175 return;
2176
Yun Park8292dcb2016-10-07 16:46:06 -07002177 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002178 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07002179
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002180 if (!iface_context) {
2181 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2182 "Interface context is NULL");
2183 return;
2184 }
2185
2186 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07002187 /* IPA offload status is already set as desired */
2188 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002189 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
2190 "IPA offload status is already set",
2191 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002192 return;
2193 }
2194
Yun Park4540e862016-11-10 16:30:06 -08002195 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2196 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2197 "invalid session id: %d, offload_type=%d, enable=%d",
2198 adapter->sessionId, offload_type, enable);
2199 return;
2200 }
2201
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302202 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002203 sizeof(ipa_offload_enable_disable));
2204 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002205 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002206 ipa_offload_enable_disable.enable = enable;
2207
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302208 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07002209 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002210 ipa_offload_enable_disable.offload_type,
2211 ipa_offload_enable_disable.vdev_id,
2212 ipa_offload_enable_disable.enable);
2213
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302214 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002215 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
2216 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302217 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08002218 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2219 __func__,
2220 ipa_offload_enable_disable.offload_type,
2221 ipa_offload_enable_disable.vdev_id,
2222 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002223 } else {
2224 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002225 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002226 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002227 }
2228}
2229
2230/**
2231 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2232 * @work: uC OP work
2233 *
2234 * Return: None
2235 */
2236static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2237{
2238 struct op_msg_type *msg;
2239 struct uc_op_work_struct *uc_op_work = container_of(work,
2240 struct uc_op_work_struct, work);
2241 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2242
2243 cds_ssr_protect(__func__);
2244
2245 msg = uc_op_work->msg;
2246 uc_op_work->msg = NULL;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302247 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002248 "%s, posted msg %d", __func__, msg->op_code);
2249
2250 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2251
2252 cds_ssr_unprotect(__func__);
2253
2254 return;
2255}
2256
2257/**
2258 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2259 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2260 * @op_msg: operation message received from firmware
2261 * @hdd_ctx: Global HDD context
2262 *
2263 * Return: None
2264 */
2265static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2266{
2267 struct hdd_ipa_priv *hdd_ipa;
2268 struct op_msg_type *msg;
2269 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302270 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002271
2272 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302273 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002274 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002275
2276 msg = (struct op_msg_type *)op_msg;
2277 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
2278
2279 if (unlikely(!hdd_ipa))
2280 goto end;
2281
2282 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302283 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002284 __func__, msg->op_code);
2285 goto end;
2286 }
2287
2288 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2289 if (uc_op_work->msg)
2290 /* When the same uC OPCODE is already pended, just return */
2291 goto end;
2292
2293 uc_op_work->msg = msg;
2294 schedule_work(&uc_op_work->work);
2295 return;
2296
2297end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302298 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002299}
2300
2301/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002302 * hdd_ipa_init_uc_op_work - init ipa uc op work
2303 * @work: struct work_struct
2304 * @work_handler: work_handler
2305 *
2306 * Return: none
2307 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002308static void hdd_ipa_init_uc_op_work(struct work_struct *work,
2309 work_func_t work_handler)
2310{
2311 INIT_WORK(work, work_handler);
2312}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002313
2314
2315/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002316 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
2317 * @hdd_ctx: Global HDD context
2318 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302319 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002320 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002321QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002322{
2323 struct ipa_wdi_in_params pipe_in;
2324 struct ipa_wdi_out_params pipe_out;
2325 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2326 p_cds_contextType cds_ctx = hdd_ctx->pcds_context;
2327 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07002328 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002329 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002330
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002331 ENTER();
2332
2333 if (!pdev || !soc) {
2334 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
2335 return QDF_STATUS_E_FAILURE;
2336 }
2337 cdp_ipa_get_resource(soc, pdev, &ipa_ctxt->ipa_resource);
2338 if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) ||
2339 (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2340 (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2341 (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2342 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2343 "IPA UC resource alloc fail");
2344 return QDF_STATUS_E_FAILURE;
2345 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002346 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2347 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302348 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2349 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002350
Anurag Chouhanffb21542016-02-17 14:33:03 +05302351 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302352
2353 if (!cds_is_driver_recovering()) {
2354 qdf_mutex_create(&ipa_ctxt->event_lock);
2355 qdf_mutex_create(&ipa_ctxt->ipa_lock);
2356 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002357
2358 /* TX PIPE */
2359 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2360 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2361 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2362 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2363 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2364 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2365 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2366 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2367 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2368 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2369 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2370 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2371 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302372 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
2374 pipe_in.sys.keep_ipa_awake = true;
2375 }
2376
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002377 pipe_in.u.dl.comp_ring_base_pa =
2378 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002379 pipe_in.u.dl.comp_ring_size =
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002380 ipa_ctxt->ipa_resource.tx_comp_ring_size *
2381 sizeof(qdf_dma_addr_t);
2382 pipe_in.u.dl.ce_ring_base_pa =
2383 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
2384 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
2385 pipe_in.u.dl.ce_ring_size =
2386 ipa_ctxt->ipa_resource.ce_sr_ring_size;
2387 pipe_in.u.dl.num_tx_buffers =
2388 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002389
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002390 qdf_mem_copy(&ipa_ctxt->cons_pipe_in,
2391 &pipe_in,
2392 sizeof(struct ipa_wdi_in_params));
2393 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
2394 IPA_CLIENT_WLAN1_CONS);
2395 if (true == ipa_ctxt->uc_loaded) {
2396 /* Connect WDI IPA PIPE */
2397 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2398 /* Micro Controller Doorbell register */
2399 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2400 "%s CONS DB pipe out 0x%x",
2401 __func__, (unsigned int)pipe_out.uc_door_bell_pa);
2402
2403 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
2404 /* WLAN TX PIPE Handle */
2405 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2406 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2407 "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x, CERZ %d, NB %d, CDBPAD 0x%x",
2408 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
2409 pipe_in.u.dl.comp_ring_size,
2410 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
2411 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
2412 pipe_in.u.dl.ce_ring_size,
2413 pipe_in.u.dl.num_tx_buffers,
2414 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
2415 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002416
2417 /* RX PIPE */
2418 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2419 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
2420 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
2421 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
2422 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2423 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
2424 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
2425 sizeof(struct sps_iovec);
2426 pipe_in.sys.notify = hdd_ipa_w2i_cb;
2427 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302428 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002429 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
2430 pipe_in.sys.keep_ipa_awake = true;
2431 }
2432
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002433 pipe_in.u.ul.rdy_ring_base_pa =
2434 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
2435 pipe_in.u.ul.rdy_ring_size =
2436 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
2437 pipe_in.u.ul.rdy_ring_rp_pa =
2438 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002439 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002440 qdf_mem_copy(&ipa_ctxt->prod_pipe_in,
2441 &pipe_in,
2442 sizeof(struct ipa_wdi_in_params));
2443 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
2444 IPA_CLIENT_WLAN1_PROD);
2445 if (true == ipa_ctxt->uc_loaded) {
2446 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2447 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2448 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
2449 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2450 "%s PROD DB pipe out 0x%x",
2451 __func__, (unsigned int)pipe_out.uc_door_bell_pa);
2452 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2453 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
2454 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
2455 pipe_in.u.ul.rdy_ring_size,
2456 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
2457 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
2458 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002459
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002460 cdp_ipa_set_doorbell_paddr(soc,
2461 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
Leo Changfdb45c32016-10-28 11:09:23 -07002462 ipa_ctxt->tx_comp_doorbell_paddr,
2463 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002464
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002465 cdp_ipa_register_op_cb(soc,
2466 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2467 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002468
2469 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08002470 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002471 hdd_ipa_uc_fw_op_event_handler);
2472 ipa_ctxt->uc_op_work[i].msg = NULL;
2473 }
2474
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302475 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002476}
2477
Leo Change3e49442015-10-26 20:07:13 -07002478/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002479 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002480 * @hdd_ctx: hdd main context
2481 *
2482 * Force shutdown IPA pipe
2483 * Independent of FW pipe status, IPA pipe shutdonw progress
2484 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2485 * independent from FW pipe status
2486 *
2487 * Return: NONE
2488 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002489static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002490{
2491 struct hdd_ipa_priv *hdd_ipa;
2492
2493 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2494 return;
2495
2496 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2497 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302498 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07002499 "IPA pipes are not down yet, force shutdown");
2500 hdd_ipa_uc_disable_pipes(hdd_ipa);
2501 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302502 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Leo Change3e49442015-10-26 20:07:13 -07002503 "IPA pipes are down, do nothing");
2504 }
2505
2506 return;
2507}
2508
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002509/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002510 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2511 * __hdd_ipa_uc_force_pipe_shutdown
2512 * @hdd_ctx: hdd main context
2513 *
2514 * Force shutdown IPA pipe
2515 * Independent of FW pipe status, IPA pipe shutdonw progress
2516 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2517 * independent from FW pipe status
2518 *
2519 * Return: NONE
2520 */
2521void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2522{
2523 cds_ssr_protect(__func__);
2524 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2525 cds_ssr_unprotect(__func__);
2526}
2527
2528/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302529 * hdd_ipa_msg_free_fn() - Free an IPA message
2530 * @buff: pointer to the IPA message
2531 * @len: length of the IPA message
2532 * @type: type of IPA message
2533 *
2534 * Return: None
2535 */
2536static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2537{
2538 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "msg type:%d, len:%d", type, len);
2539 ghdd_ipa->stats.num_free_msg++;
2540 qdf_mem_free(buff);
2541}
2542
Govind Singh9c58eba2016-09-02 16:23:06 +05302543/**
jge62037862016-12-09 10:44:33 +08002544 * hdd_ipa_uc_send_evt() - send event to ipa
2545 * @hdd_ctx: pointer to hdd context
2546 * @type: event type
2547 * @mac_addr: pointer to mac address
2548 *
2549 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05302550 *
2551 * Return: 0 - Success
2552 */
jge62037862016-12-09 10:44:33 +08002553static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
2554 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05302555{
jge62037862016-12-09 10:44:33 +08002556 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05302557 struct ipa_msg_meta meta;
2558 struct ipa_wlan_msg *msg;
2559 int ret = 0;
jge62037862016-12-09 10:44:33 +08002560
2561 meta.msg_len = sizeof(struct ipa_wlan_msg);
2562 msg = qdf_mem_malloc(meta.msg_len);
2563 if (msg == NULL) {
2564 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2565 "msg allocation failed");
2566 return -ENOMEM;
2567 }
2568
2569 meta.msg_type = type;
2570 strlcpy(msg->name, adapter->dev->name,
2571 IPA_RESOURCE_NAME_MAX);
2572 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
2573 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
2574 msg->name, meta.msg_type);
2575 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2576 if (ret) {
2577 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2578 "%s: Evt: %d fail:%d",
2579 msg->name, meta.msg_type, ret);
2580 qdf_mem_free(msg);
2581 return ret;
2582 }
2583
2584 hdd_ipa->stats.num_send_msg++;
2585
2586 return ret;
2587}
2588
2589/**
2590 * hdd_ipa_uc_disconnect_client() - send client disconnect event
2591 * @hdd_ctx: pointer to hdd adapter
2592 *
2593 * Send disconnect client event to IPA driver during SSR
2594 *
2595 * Return: 0 - Success
2596 */
2597static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
2598{
2599 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2600 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05302601 int i;
2602
2603 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2604 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2605 continue;
2606 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08002607 (!adapter->aStaInfo[i].isDeauthInProgress) &&
2608 hdd_ipa->sap_num_connected_sta) {
2609 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
2610 adapter->aStaInfo[i].macAddrSTA.bytes);
2611 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05302612 }
2613 }
2614
2615 return ret;
2616}
2617
2618/**
jge62037862016-12-09 10:44:33 +08002619 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
2620 * @hdd_ctx: pointer to hdd adapter
2621 *
2622 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05302623 *
2624 * Return: 0 - Success
2625 */
jge62037862016-12-09 10:44:33 +08002626
2627static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
2628{
2629 int ret = 0;
2630
2631 if (adapter->ipa_context)
2632 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
2633 adapter->dev->dev_addr);
2634
2635 return ret;
2636}
2637
2638#ifdef IPA_UC_STA_OFFLOAD
2639/**
2640 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
2641 * @hdd_ctx: pointer to hdd adapter
2642 *
2643 * Send disconnect sta event to IPA driver during SSR
2644 *
2645 * Return: 0 - Success
2646 */
2647static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2648{
2649 hdd_station_ctx_t *pHddStaCtx;
2650 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2651 int ret = 0;
2652
2653 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa) &&
2654 hdd_ipa->sta_connected) {
2655 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2656 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
2657 pHddStaCtx->conn_info.bssId);
2658 }
2659
2660 return ret;
2661}
2662#else
2663static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2664{
2665 return 0;
2666}
2667
2668#endif
2669
2670/**
2671 * hdd_ipa_uc_disconnect() - send disconnect ipa event
2672 * @hdd_ctx: pointer to hdd context
2673 *
2674 * Send disconnect event to IPA driver during SSR
2675 *
2676 * Return: 0 - Success
2677 */
2678static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05302679{
2680 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2681 QDF_STATUS status;
2682 hdd_adapter_t *adapter;
2683 int ret = 0;
2684
Govind Singh9c58eba2016-09-02 16:23:06 +05302685 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2686 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2687 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08002688 if (adapter->device_mode == QDF_SAP_MODE) {
2689 hdd_ipa_uc_disconnect_client(adapter);
2690 hdd_ipa_uc_disconnect_ap(adapter);
2691 } else if (adapter->device_mode == QDF_STA_MODE) {
2692 hdd_ipa_uc_disconnect_sta(adapter);
2693 }
2694
Govind Singh9c58eba2016-09-02 16:23:06 +05302695 status = hdd_get_next_adapter(
2696 hdd_ctx, adapter_node, &next);
2697 adapter_node = next;
2698 }
2699
2700 return ret;
2701}
2702
2703/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002704 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002705 *
2706 * Deinit basic IPA UC host side to be in sync reloaded FW during
2707 * SSR
2708 *
2709 * Return: 0 - Success
2710 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002711static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002712{
2713 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2714 int idx;
2715 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302716 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002717
Arun Khandavallicc544b32017-01-30 19:52:16 +05302718 if (!hdd_ipa)
2719 return 0;
2720
2721 hdd_ctx = hdd_ipa->hdd_ctx;
2722 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002723 return 0;
2724
jge62037862016-12-09 10:44:33 +08002725 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302726 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08002727
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002728 /* Clean up HDD IPA interfaces */
2729 for (idx = 0; (hdd_ipa->num_iface > 0) &&
2730 (idx < HDD_IPA_MAX_IFACE); idx++) {
2731 iface_context = &hdd_ipa->iface_context[idx];
2732 if (iface_context && iface_context->adapter)
2733 hdd_ipa_cleanup_iface(iface_context);
2734 }
2735
2736 /* After SSR, wlan driver reloads FW again. But we need to protect
2737 * IPA submodule during SSR transient state. So deinit basic IPA
2738 * UC host side to be in sync with reloaded FW during SSR
2739 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08002740 if (!hdd_ipa->ipa_pipes_down)
2741 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302743 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002744 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2745 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
2746 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
2747 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302748 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002749
Arun Khandavallicc544b32017-01-30 19:52:16 +05302750 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2751 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
2752 __func__, hdd_ipa->tx_pipe_handle);
2753 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
2754
2755 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2756 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
2757 __func__, hdd_ipa->rx_pipe_handle);
2758 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
2759
Guolei Bianca144d82016-11-10 11:07:42 +08002760 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
2761 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
2762
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002763 /* Full IPA driver cleanup not required since wlan driver is now
2764 * unloaded and reloaded after SSR.
2765 */
2766 return 0;
2767}
2768
2769/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002770 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
2771 *
2772 * Deinit basic IPA UC host side to be in sync reloaded FW during
2773 * SSR
2774 *
2775 * Return: 0 - Success
2776 */
2777int hdd_ipa_uc_ssr_deinit(void)
2778{
2779 int ret;
2780
2781 cds_ssr_protect(__func__);
2782 ret = __hdd_ipa_uc_ssr_deinit();
2783 cds_ssr_unprotect(__func__);
2784
2785 return ret;
2786}
2787
2788/**
2789 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002790 *
2791 * Init basic IPA UC host side to be in sync with reloaded FW after
2792 * SSR to resume IPA UC operations
2793 *
2794 * Return: 0 - Success
2795 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302796static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002797{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002798
Arun Khandavallicc544b32017-01-30 19:52:16 +05302799 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2800 int i;
2801 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302802
2803 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
2804 return 0;
2805
Arun Khandavallicc544b32017-01-30 19:52:16 +05302806 /* Create the interface context */
2807 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2808 iface_context = &hdd_ipa->iface_context[i];
2809 iface_context->hdd_ipa = hdd_ipa;
2810 iface_context->cons_client =
2811 hdd_ipa_adapter_2_client[i].cons_client;
2812 iface_context->prod_client =
2813 hdd_ipa_adapter_2_client[i].prod_client;
2814 iface_context->iface_id = i;
2815 iface_context->adapter = NULL;
2816 }
2817 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
2818 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
2819 hdd_ipa->vdev_offload_enabled[i] = false;
2820 }
2821
2822 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2823 hdd_ipa->resource_loading = false;
2824 hdd_ipa->resource_unloading = false;
2825 hdd_ipa->sta_connected = 0;
2826 hdd_ipa->ipa_pipes_down = true;
2827 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302828 }
2829
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002830 return 0;
2831}
Leo Chang3bc8fed2015-11-13 10:59:47 -08002832
2833/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002834 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
2835 *
2836 * Init basic IPA UC host side to be in sync with reloaded FW after
2837 * SSR to resume IPA UC operations
2838 *
2839 * Return: 0 - Success
2840 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302841int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002842{
2843 int ret;
2844
2845 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302846 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002847 cds_ssr_unprotect(__func__);
2848
2849 return ret;
2850}
2851
2852/**
2853 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08002854 * @hdd_ctx: Global HDD context
2855 * @skb: skb sent to IPA
2856 * @session_id: send packet instance session id
2857 *
2858 * Send TX packet which generated by system to IPA.
2859 * This routine only will be used for function verification
2860 *
2861 * Return: NULL packet sent to IPA properly
2862 * NULL invalid packet drop
2863 * skb packet not sent to IPA. legacy data path should handle
2864 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002865static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002866 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07002867{
Leo Chang3bc8fed2015-11-13 10:59:47 -08002868 struct ipa_header *ipa_header;
2869 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002870 struct hdd_ipa_priv *hdd_ipa;
2871
2872 if (wlan_hdd_validate_context(hdd_ctx))
2873 return skb;
2874
2875 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002876
2877 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2878 return skb;
2879
Leo Chang07b28f62016-05-11 12:29:22 -07002880 if (!hdd_ipa)
2881 return skb;
2882
2883 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
2884 return skb;
2885
Leo Changcc923e22016-06-16 15:29:03 -07002886 if (skb_headroom(skb) <
2887 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07002888 return skb;
2889
Leo Chang3bc8fed2015-11-13 10:59:47 -08002890 ipa_header = (struct ipa_header *) skb_push(skb,
2891 sizeof(struct ipa_header));
2892 if (!ipa_header) {
2893 /* No headroom, legacy */
2894 return skb;
2895 }
2896 memset(ipa_header, 0, sizeof(*ipa_header));
2897 ipa_header->vdev_id = 0;
2898
2899 frag_header = (struct frag_header *) skb_push(skb,
2900 sizeof(struct frag_header));
2901 if (!frag_header) {
2902 /* No headroom, drop */
2903 kfree_skb(skb);
2904 return NULL;
2905 }
2906 memset(frag_header, 0, sizeof(*frag_header));
2907 frag_header->length = skb->len - sizeof(struct frag_header)
2908 - sizeof(struct ipa_header);
2909
2910 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
2911 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07002912}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002913
2914/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002915 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
2916 * @hdd_ctx: Global HDD context
2917 * @skb: skb sent to IPA
2918 * @session_id: send packet instance session id
2919 *
2920 * Send TX packet which generated by system to IPA.
2921 * This routine only will be used for function verification
2922 *
2923 * Return: NULL packet sent to IPA properly
2924 * NULL invalid packet drop
2925 * skb packet not sent to IPA. legacy data path should handle
2926 */
2927struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
2928 struct sk_buff *skb, uint8_t session_id)
2929{
2930 struct sk_buff *ret;
2931
2932 cds_ssr_protect(__func__);
2933 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
2934 cds_ssr_unprotect(__func__);
2935
2936 return ret;
2937}
2938
2939/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002940 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
2941 * @work: scheduled work
2942 *
2943 * When IPA resources are released in hdd_ipa_rm_try_release() we do
2944 * not want to immediately release the wake lock since the system
2945 * would then potentially try to suspend when there is a healthy data
2946 * rate. Deferred work is scheduled and this function handles the
2947 * work. When this function is called, if the IPA resource is still
2948 * released then we release the wake lock.
2949 *
2950 * Return: None
2951 */
2952static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
2953{
2954 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
2955 struct hdd_ipa_priv,
2956 wake_lock_work);
2957
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302958 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002959
2960 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
2961 goto end;
2962
2963 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302964 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002965 WIFI_POWER_EVENT_WAKELOCK_IPA);
2966
2967end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302968 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002969}
2970
2971/**
2972 * hdd_ipa_rm_request() - Request resource from IPA
2973 * @hdd_ipa: Global HDD IPA context
2974 *
2975 * Return: 0 on success, negative errno on error
2976 */
2977static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
2978{
2979 int ret = 0;
2980
2981 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2982 return 0;
2983
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302984 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002985
2986 switch (hdd_ipa->rm_state) {
2987 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302988 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002989 return 0;
2990 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302991 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002992 return -EINPROGRESS;
2993 case HDD_IPA_RM_RELEASED:
2994 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
2995 break;
2996 }
2997
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302998 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002999
3000 ret = ipa_rm_inactivity_timer_request_resource(
3001 IPA_RM_RESOURCE_WLAN_PROD);
3002
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303003 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003004 if (ret == 0) {
3005 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3006 hdd_ipa->stats.num_rm_grant_imm++;
3007 }
3008
3009 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3010 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303011 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003012 WIFI_POWER_EVENT_WAKELOCK_IPA);
3013 hdd_ipa->wake_lock_released = false;
3014 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303015 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003016
3017 return ret;
3018}
3019
3020/**
3021 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3022 * @hdd_ipa: Global HDD IPA context
3023 *
3024 * Return: 0 if resources released, negative errno otherwise
3025 */
3026static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3027{
3028 int ret = 0;
3029
3030 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3031 return 0;
3032
3033 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3034 return -EAGAIN;
3035
3036 spin_lock_bh(&hdd_ipa->q_lock);
3037 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
3038 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
3039 spin_unlock_bh(&hdd_ipa->q_lock);
3040 return -EAGAIN;
3041 }
3042 spin_unlock_bh(&hdd_ipa->q_lock);
3043
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303044 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003045
Nirav Shahcbc6d722016-03-01 16:24:53 +05303046 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303047 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003048 return -EAGAIN;
3049 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303050 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003051
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303052 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003053 switch (hdd_ipa->rm_state) {
3054 case HDD_IPA_RM_GRANTED:
3055 break;
3056 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303057 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003058 return -EINPROGRESS;
3059 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303060 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003061 return 0;
3062 }
3063
3064 /* IPA driver returns immediately so set the state here to avoid any
3065 * race condition.
3066 */
3067 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3068 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303069 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003070
3071 ret =
3072 ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
3073
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303074 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003075 if (unlikely(ret != 0)) {
3076 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3077 WARN_ON(1);
3078 }
3079
3080 /*
3081 * If wake_lock is released immediately, kernel would try to suspend
3082 * immediately as well, Just avoid ping-pong between suspend-resume
3083 * while there is healthy amount of data transfer going on by
3084 * releasing the wake_lock after some delay.
3085 */
3086 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3087 msecs_to_jiffies
3088 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3089
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303090 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003091
3092 return ret;
3093}
3094
3095/**
3096 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3097 * @user_data: user data registered with IPA
3098 * @event: the IPA resource manager event that occurred
3099 * @data: the data associated with the event
3100 *
3101 * Return: None
3102 */
3103static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3104 unsigned long data)
3105{
3106 struct hdd_ipa_priv *hdd_ipa = user_data;
3107
3108 if (unlikely(!hdd_ipa))
3109 return;
3110
3111 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3112 return;
3113
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303114 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003115
3116 switch (event) {
3117 case IPA_RM_RESOURCE_GRANTED:
3118 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3119 /* RM Notification comes with ISR context
3120 * it should be serialized into work queue to avoid
3121 * ISR sleep problem
3122 */
3123 hdd_ipa->uc_rm_work.event = event;
3124 schedule_work(&hdd_ipa->uc_rm_work.work);
3125 break;
3126 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303127 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003128 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303129 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003130 hdd_ipa->stats.num_rm_grant++;
3131 break;
3132
3133 case IPA_RM_RESOURCE_RELEASED:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303134 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135 hdd_ipa->resource_unloading = false;
3136 break;
3137
3138 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303139 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003140 break;
3141 }
3142}
3143
3144/**
3145 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3146 *
3147 * Callback function registered with IPA that is called when IPA wants
3148 * to release the WLAN consumer resource
3149 *
3150 * Return: 0 if the request is granted, negative errno otherwise
3151 */
3152static int hdd_ipa_rm_cons_release(void)
3153{
3154 return 0;
3155}
3156
3157/**
3158 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3159 *
3160 * Callback function registered with IPA that is called when IPA wants
3161 * to access the WLAN consumer resource
3162 *
3163 * Return: 0 if the request is granted, negative errno otherwise
3164 */
3165static int hdd_ipa_rm_cons_request(void)
3166{
Yun Park4d8b60a2015-10-22 13:59:32 -07003167 int ret = 0;
3168
3169 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303170 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003171 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003172 __func__);
3173 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003174 ret = -EINPROGRESS;
3175 } else if (ghdd_ipa->resource_unloading) {
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 unloading in progress",
3178 __func__);
3179 ghdd_ipa->pending_cons_req = true;
3180 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003181 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003182
3183 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003184}
3185
3186/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003187 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003188 * @hdd_ctx: Global HDD context
3189 * @tx_packets: Number of packets transmitted in the last sample period
3190 * @rx_packets: Number of packets received in the last sample period
3191 *
3192 * Return: 0 on success, negative errno on error
3193 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003194static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003195 uint64_t rx_packets)
3196{
3197 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003198 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003199 struct ipa_rm_perf_profile profile;
3200 int ret;
3201
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003202 if (wlan_hdd_validate_context(hdd_ctx))
3203 return 0;
3204
3205 hdd_ipa = hdd_ctx->hdd_ipa;
3206
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003207 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3208 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3209 return 0;
3210
3211 memset(&profile, 0, sizeof(profile));
3212
3213 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3214 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3215 else if (tx_packets >
3216 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3217 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3218 else
3219 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3220
3221 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3222 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3223 else if (rx_packets >
3224 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3225 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3226 else
3227 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3228
Yun Park8f289c82016-10-18 16:38:21 -07003229 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003230 "CONS perf curr: %d, next: %d",
3231 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Park8f289c82016-10-18 16:38:21 -07003232 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003233 "PROD perf curr: %d, next: %d",
3234 hdd_ipa->curr_prod_bw, next_prod_bw);
3235
3236 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003237 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003238 hdd_ipa->curr_cons_bw, next_cons_bw);
3239 profile.max_supported_bandwidth_mbps = next_cons_bw;
3240 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3241 &profile);
3242 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003243 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003244
3245 return ret;
3246 }
3247 hdd_ipa->curr_cons_bw = next_cons_bw;
3248 hdd_ipa->stats.num_cons_perf_req++;
3249 }
3250
3251 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003252 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003253 hdd_ipa->curr_prod_bw, next_prod_bw);
3254 profile.max_supported_bandwidth_mbps = next_prod_bw;
3255 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3256 &profile);
3257 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003258 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003259 return ret;
3260 }
3261 hdd_ipa->curr_prod_bw = next_prod_bw;
3262 hdd_ipa->stats.num_prod_perf_req++;
3263 }
3264
3265 return 0;
3266}
3267
3268/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003269 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3270 * @hdd_ctx: Global HDD context
3271 * @tx_packets: Number of packets transmitted in the last sample period
3272 * @rx_packets: Number of packets received in the last sample period
3273 *
3274 * Return: 0 on success, negative errno on error
3275 */
3276int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3277 uint64_t rx_packets)
3278{
3279 int ret;
3280
3281 cds_ssr_protect(__func__);
3282 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3283 cds_ssr_unprotect(__func__);
3284
3285 return ret;
3286}
3287
3288/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003289 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3290 * @work: struct work_struct
3291 * @work_handler: work_handler
3292 *
3293 * Return: none
3294 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003295static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3296 work_func_t work_handler)
3297{
3298 INIT_WORK(work, work_handler);
3299}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003300
3301/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003302 * hdd_ipa_setup_rm() - Setup IPA resource management
3303 * @hdd_ipa: Global HDD IPA context
3304 *
3305 * Return: 0 on success, negative errno on error
3306 */
3307static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3308{
3309 struct ipa_rm_create_params create_params = { 0 };
3310 int ret;
3311
3312 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3313 return 0;
3314
Rajeev Kumar217f2172016-01-06 18:11:55 -08003315 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3316 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003317 memset(&create_params, 0, sizeof(create_params));
3318 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3319 create_params.reg_params.user_data = hdd_ipa;
3320 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3321 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3322
3323 ret = ipa_rm_create_resource(&create_params);
3324 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303325 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003326 "Create RM resource failed: %d", ret);
3327 goto setup_rm_fail;
3328 }
3329
3330 memset(&create_params, 0, sizeof(create_params));
3331 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3332 create_params.request_resource = hdd_ipa_rm_cons_request;
3333 create_params.release_resource = hdd_ipa_rm_cons_release;
3334 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3335
3336 ret = ipa_rm_create_resource(&create_params);
3337 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303338 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003339 "Create RM CONS resource failed: %d", ret);
3340 goto delete_prod;
3341 }
3342
3343 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3344 IPA_RM_RESOURCE_APPS_CONS);
3345
3346 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3347 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3348 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303349 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003350 ret);
3351 goto timer_init_failed;
3352 }
3353
3354 /* Set the lowest bandwidth to start with */
3355 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3356
3357 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303358 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003359 "Set perf level failed: %d", ret);
3360 goto set_perf_failed;
3361 }
3362
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303363 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3365 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303366 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003367 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3368 hdd_ipa->wake_lock_released = true;
3369 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3370
3371 return ret;
3372
3373set_perf_failed:
3374 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3375
3376timer_init_failed:
3377 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3378
3379delete_prod:
3380 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3381
3382setup_rm_fail:
3383 return ret;
3384}
3385
3386/**
3387 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3388 * @hdd_ipa: Global HDD IPA context
3389 *
3390 * Destroys all resources associated with the IPA resource manager
3391 *
3392 * Return: None
3393 */
3394static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3395{
3396 int ret;
3397
3398 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3399 return;
3400
3401 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303402 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403
3404#ifdef WLAN_OPEN_SOURCE
3405 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
3406#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303407 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003408
3409 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3410
3411 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3412 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303413 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003414 "RM PROD resource delete failed %d", ret);
3415
3416 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3417 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303418 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003419 "RM CONS resource delete failed %d", ret);
3420}
3421
3422/**
3423 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3424 * @skb: network buffer
3425 * @adapter: network adapter
3426 *
3427 * Called when a network buffer is received which should not be routed
3428 * to the IPA module.
3429 *
3430 * Return: None
3431 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303432static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003433 hdd_adapter_t *adapter)
3434{
3435 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3436 unsigned int cpu_index;
3437
3438 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303439 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003440 adapter);
3441 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003442 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003443 return;
3444 }
3445
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003446 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003447 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
3452 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3453 skb->dev = adapter->dev;
3454 skb->protocol = eth_type_trans(skb, skb->dev);
3455 skb->ip_summed = CHECKSUM_NONE;
3456
3457 cpu_index = wlan_hdd_get_cpu();
3458
3459 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
3460 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
3461 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3462 else
3463 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3464
3465 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
3466 adapter->dev->last_rx = jiffies;
3467}
3468
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003469/**
Leo Chang69c39692016-10-12 20:11:12 -07003470 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3471 * @hdd_ipa: pointer to hdd ipa context
3472 * @adapter: network adapter
3473 * @skb: data pointer
3474 *
3475 * if exception packet has set forward bit, copied new packet should be
3476 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3477 * put into pm queue and tx procedure will be differed
3478 *
3479 * Return: None
3480 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003481static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
3482 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003483{
Leo Chang69c39692016-10-12 20:11:12 -07003484 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3485
Leo Chang69c39692016-10-12 20:11:12 -07003486 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
3487 /* WLAN subsystem is in suspend, put int queue */
3488 if (hdd_ipa->suspended) {
3489 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3490 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3491 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003492 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3493 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003494 pm_tx_cb->exception = true;
3495 pm_tx_cb->adapter = adapter;
3496 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003497 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003498 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3499 hdd_ipa->stats.num_tx_queued++;
3500 } else {
3501 /* Resume, put packet into WLAN TX */
3502 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003503 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003504 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3505 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003506 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003507 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003508 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003509 hdd_ipa->ipa_tx_forward++;
3510 }
3511 }
3512}
3513
3514/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003515 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3516 * @hdd_ipa: pointer to HDD IPA struct
3517 * @adapter: hdd adapter pointer
3518 * @desc: Firmware descriptor
3519 * @skb: Data buffer
3520 *
3521 * Return:
3522 * HDD_IPA_FORWARD_PKT_NONE
3523 * HDD_IPA_FORWARD_PKT_DISCARD
3524 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3525 *
3526 */
3527
3528static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3529 struct hdd_ipa_priv *hdd_ipa,
3530 hdd_adapter_t *adapter,
3531 uint8_t desc,
3532 qdf_nbuf_t skb)
3533{
3534 int ret = HDD_IPA_FORWARD_PKT_NONE;
3535
3536 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303537 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003538 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
3539 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303540 /* Drop the packet*/
3541 hdd_ipa->stats.num_tx_fwd_err++;
3542 kfree_skb(skb);
3543 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3544 return ret;
3545 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003546 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3547 "Forward packet to Tx (fw_desc=%d)", desc);
3548 hdd_ipa->ipa_tx_forward++;
3549
3550 if ((desc & FW_RX_DESC_DISCARD_M)) {
3551 hdd_ipa_forward(hdd_ipa, adapter, skb);
3552 hdd_ipa->ipa_rx_internel_drop_count++;
3553 hdd_ipa->ipa_rx_discard++;
3554 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3555 } else {
3556 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
3557 if (cloned_skb)
3558 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3559 else
3560 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3561 "%s: tx skb alloc failed",
3562 __func__);
3563 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3564 }
3565 }
3566
3567 return ret;
3568}
3569
3570/**
Leo Chang69c39692016-10-12 20:11:12 -07003571 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003572 * @priv: pointer to private data registered with IPA (we register a
3573 * pointer to the global IPA context)
3574 * @evt: the IPA event which triggered the callback
3575 * @data: data associated with the event
3576 *
3577 * Return: None
3578 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003579static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003580 unsigned long data)
3581{
3582 struct hdd_ipa_priv *hdd_ipa = NULL;
3583 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303584 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003585 uint8_t iface_id;
3586 uint8_t session_id;
3587 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003588 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003589 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590
3591 hdd_ipa = (struct hdd_ipa_priv *)priv;
3592
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003593 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3594 return;
3595
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003596 switch (evt) {
3597 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303598 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003599
3600 /*
3601 * When SSR is going on or driver is unloading,
3602 * just drop the packets.
3603 */
3604 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
3605 if (0 != status) {
3606 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3607 "Invalid context: drop packet");
3608 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3609 kfree_skb(skb);
3610 return;
3611 }
3612
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3614 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003615 iface_id = hdd_ipa->vdev_to_iface[session_id];
Govind Singhb6a89772016-08-12 11:23:35 +05303616 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003617 "IPA_RECEIVE: session_id=%u, iface_id=%u",
3618 session_id, iface_id);
3619 } else {
3620 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
3621 }
3622
3623 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303624 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003625 "IPA_RECEIVE: Invalid iface_id: %u",
3626 iface_id);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303627 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_INFO_HIGH,
Yun Parkb187d542016-11-14 18:10:04 -08003628 "w2i -- skb",
3629 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003630 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003631 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003632 return;
3633 }
3634
3635 iface_context = &hdd_ipa->iface_context[iface_id];
3636 adapter = iface_context->adapter;
3637
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303638 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003639 "w2i -- skb",
3640 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003641 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3642 hdd_ipa->stats.num_rx_excep++;
3643 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
3644 } else {
3645 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
3646 }
3647
3648 iface_context->stats.num_rx_ipa_excep++;
3649
3650 /* Disable to forward Intra-BSS Rx packets when
3651 * ap_isolate=1 in hostapd.conf
3652 */
Yun Park046101c2016-09-02 15:32:14 -07003653 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003654 /*
3655 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3656 * all Rx packets to IPA uC, which need to be forwarded
3657 * to other interface.
3658 * And, IPA driver will send back to WLAN host driver
3659 * through exception pipe with fw_desc field set by FW.
3660 * Here we are checking fw_desc field for FORWARD bit
3661 * set, and forward to Tx. Then copy to kernel stack
3662 * only when DISCARD bit is not set.
3663 */
3664 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003665 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3666 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3667 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003668 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003669 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303670 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003671 "Intra-BSS FWD is disabled-skip forward to Tx");
3672 }
3673
3674 hdd_ipa_send_skb_to_network(skb, adapter);
3675 break;
3676
3677 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303678 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003679 "w2i cb wrong event: 0x%x", evt);
3680 return;
3681 }
3682}
3683
3684/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003685 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3686 * @priv: pointer to private data registered with IPA (we register a
3687 * pointer to the global IPA context)
3688 * @evt: the IPA event which triggered the callback
3689 * @data: data associated with the event
3690 *
3691 * Return: None
3692 */
3693static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3694 unsigned long data)
3695{
3696 cds_ssr_protect(__func__);
3697 __hdd_ipa_w2i_cb(priv, evt, data);
3698 cds_ssr_unprotect(__func__);
3699}
3700
3701/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003702 * hdd_ipa_nbuf_cb() - IPA TX complete callback
3703 * @skb: packet buffer which was transmitted
3704 *
3705 * Return: None
3706 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303707void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708{
3709 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3710
Govind Singhb6a89772016-08-12 11:23:35 +05303711 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05303712 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003713 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303714 ipa_free_skb((struct ipa_rx_data *)
3715 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003716
3717 hdd_ipa->stats.num_tx_comp_cnt++;
3718
3719 atomic_dec(&hdd_ipa->tx_ref_cnt);
3720
3721 hdd_ipa_rm_try_release(hdd_ipa);
3722}
3723
3724/**
3725 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
3726 * @iface_context: interface-specific IPA context
3727 * @ipa_tx_desc: packet data descriptor
3728 *
3729 * Return: None
3730 */
3731static void hdd_ipa_send_pkt_to_tl(
3732 struct hdd_ipa_iface_context *iface_context,
3733 struct ipa_rx_data *ipa_tx_desc)
3734{
3735 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003736 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303737 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003738
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303739 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003740 adapter = iface_context->adapter;
3741 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303742 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003743 ipa_free_skb(ipa_tx_desc);
3744 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303745 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003746 hdd_ipa_rm_try_release(hdd_ipa);
3747 return;
3748 }
3749
3750 /*
3751 * During CAC period, data packets shouldn't be sent over the air so
3752 * drop all the packets here
3753 */
3754 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
3755 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303756 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003757 iface_context->stats.num_tx_cac_drop++;
3758 hdd_ipa_rm_try_release(hdd_ipa);
3759 return;
3760 }
3761
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003762 ++adapter->stats.tx_packets;
3763
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303764 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003765
3766 skb = ipa_tx_desc->skb;
3767
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303768 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303769 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003770 /* FIXME: This is broken. No such field in cb any more:
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08003771 * NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb;
3772 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003773 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05303774 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003775 ipa_tx_desc->dma_addr
3776 + HDD_IPA_WLAN_FRAG_HEADER
3777 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003778 ipa_tx_desc->skb->len -=
3779 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
3780 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05303781 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003782
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003783 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303784 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003785
3786 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
3787
Leo Changfdb45c32016-10-28 11:09:23 -07003788 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003789 (struct cdp_vdev *)iface_context->tl_context,
3790 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303792 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003793 ipa_free_skb(ipa_tx_desc);
3794 iface_context->stats.num_tx_err++;
3795 hdd_ipa_rm_try_release(hdd_ipa);
3796 return;
3797 }
3798
3799 atomic_inc(&hdd_ipa->tx_ref_cnt);
3800
3801 iface_context->stats.num_tx++;
3802
3803}
3804
3805/**
Leo Chang11545d62016-10-17 14:53:50 -07003806 * hdd_ipa_is_present() - get IPA hw status
3807 * @hdd_ctx: pointer to hdd context
3808 *
3809 * ipa_uc_reg_rdyCB is not directly designed to check
3810 * ipa hw status. This is an undocumented function which
3811 * has confirmed with IPA team.
3812 *
3813 * Return: true - ipa hw present
3814 * false - ipa hw not present
3815 */
3816bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
3817{
3818 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07003819 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07003820 return true;
3821 else
3822 return false;
3823}
3824
3825/**
Leo Chang69c39692016-10-12 20:11:12 -07003826 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003827 * @work: pointer to the scheduled work
3828 *
3829 * Called during PM resume to send packets to TL which were queued
3830 * while host was in the process of suspending.
3831 *
3832 * Return: None
3833 */
Leo Chang69c39692016-10-12 20:11:12 -07003834static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003835{
3836 struct hdd_ipa_priv *hdd_ipa = container_of(work,
3837 struct hdd_ipa_priv,
3838 pm_work);
3839 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303840 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003841 uint32_t dequeued = 0;
3842
Leo Chang69c39692016-10-12 20:11:12 -07003843 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
3844 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303845 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303846 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
3847 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303848 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003849
3850 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003851 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07003852 if (pm_tx_cb->exception) {
3853 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3854 "FLUSH EXCEPTION");
3855 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
3856 } else {
3857 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07003859 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303860 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003861 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303862 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07003863 qdf_wake_lock_release(&hdd_ipa->wake_lock,
3864 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003865
3866 hdd_ipa->stats.num_tx_dequeued += dequeued;
3867 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
3868 hdd_ipa->stats.num_max_pm_queue = dequeued;
3869}
3870
3871/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003872 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003873 * @priv: pointer to private data registered with IPA (we register a
3874 * pointer to the interface-specific IPA context)
3875 * @evt: the IPA event which triggered the callback
3876 * @data: data associated with the event
3877 *
3878 * Return: None
3879 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003880static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003881 unsigned long data)
3882{
3883 struct hdd_ipa_priv *hdd_ipa = NULL;
3884 struct ipa_rx_data *ipa_tx_desc;
3885 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303886 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003887 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303888 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003889
Mukul Sharma81661ae2015-10-30 20:26:02 +05303890 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003891 ipa_tx_desc = (struct ipa_rx_data *)data;
3892 hdd_ipa = iface_context->hdd_ipa;
3893
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003894 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003895 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
3896 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897 iface_context->stats.num_tx_drop++;
3898 return;
3899 }
3900
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003901 /*
3902 * When SSR is going on or driver is unloading, just drop the packets.
3903 * During SSR, there is no use in queueing the packets as STA has to
3904 * connect back any way
3905 */
3906 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303907 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003908 ipa_free_skb(ipa_tx_desc);
3909 iface_context->stats.num_tx_drop++;
3910 return;
3911 }
3912
3913 skb = ipa_tx_desc->skb;
3914
Yun Parkb187d542016-11-14 18:10:04 -08003915 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
3916 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003917
3918 /*
3919 * If PROD resource is not requested here then there may be cases where
3920 * IPA hardware may be clocked down because of not having proper
3921 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
3922 * workaround to request PROD resource while data is going over CONS
3923 * pipe to prevent the IPA hardware clockdown.
3924 */
3925 hdd_ipa_rm_request(hdd_ipa);
3926
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303927 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003928 /*
3929 * If host is still suspended then queue the packets and these will be
3930 * drained later when resume completes. When packet is arrived here and
3931 * host is suspended, this means that there is already resume is in
3932 * progress.
3933 */
3934 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303935 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003936 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
3937 pm_tx_cb->iface_context = iface_context;
3938 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303939 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003940 hdd_ipa->stats.num_tx_queued++;
3941
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303942 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003943 return;
3944 }
3945
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303946 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003947
3948 /*
3949 * If we are here means, host is not suspended, wait for the work queue
3950 * to finish.
3951 */
3952#ifdef WLAN_OPEN_SOURCE
3953 flush_work(&hdd_ipa->pm_work);
3954#endif
3955
3956 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
3957}
3958
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003959/*
3960 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
3961 * @priv: pointer to private data registered with IPA (we register a
3962 * pointer to the interface-specific IPA context)
3963 * @evt: the IPA event which triggered the callback
3964 * @data: data associated with the event
3965 *
3966 * Return: None
3967 */
3968static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
3969 unsigned long data)
3970{
3971 cds_ssr_protect(__func__);
3972 __hdd_ipa_i2w_cb(priv, evt, data);
3973 cds_ssr_unprotect(__func__);
3974}
3975
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003976/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003977 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003978 * @hdd_ctx: Global HDD context
3979 *
3980 * Return: 0 on success, negativer errno on error
3981 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003982static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003983{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003984 struct hdd_ipa_priv *hdd_ipa;
3985
3986 if (wlan_hdd_validate_context(hdd_ctx))
3987 return 0;
3988
3989 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003990
3991 if (!hdd_ipa_is_enabled(hdd_ctx))
3992 return 0;
3993
3994 /*
3995 * Check if IPA is ready for suspend, If we are here means, there is
3996 * high chance that suspend would go through but just to avoid any race
3997 * condition after suspend started, these checks are conducted before
3998 * allowing to suspend.
3999 */
4000 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4001 return -EAGAIN;
4002
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304003 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004004
4005 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304006 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004007 return -EAGAIN;
4008 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304009 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004010
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304011 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304013 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004014
4015 return 0;
4016}
4017
4018/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004019 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4020 * @hdd_ctx: Global HDD context
4021 *
4022 * Return: 0 on success, negativer errno on error
4023 */
4024int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4025{
4026 int ret;
4027
4028 cds_ssr_protect(__func__);
4029 ret = __hdd_ipa_suspend(hdd_ctx);
4030 cds_ssr_unprotect(__func__);
4031
4032 return ret;
4033}
4034
4035/**
4036 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004037 * hdd_ctx: Global HDD context
4038 *
4039 * Return: 0 on success, negative errno on error
4040 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004041static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004042{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004043 struct hdd_ipa_priv *hdd_ipa;
4044
4045 if (wlan_hdd_validate_context(hdd_ctx))
4046 return 0;
4047
4048 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004049
4050 if (!hdd_ipa_is_enabled(hdd_ctx))
4051 return 0;
4052
4053 schedule_work(&hdd_ipa->pm_work);
4054
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304055 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004056 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304057 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004058
4059 return 0;
4060}
4061
4062/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004063 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4064 * hdd_ctx: Global HDD context
4065 *
4066 * Return: 0 on success, negative errno on error
4067 */
4068int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4069{
4070 int ret;
4071
4072 cds_ssr_protect(__func__);
4073 ret = __hdd_ipa_resume(hdd_ctx);
4074 cds_ssr_unprotect(__func__);
4075
4076 return ret;
4077}
4078
4079/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004080 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4081 * @hdd_ipa: Global HDD IPA context
4082 *
4083 * Return: 0 on success, negative errno on error
4084 */
4085static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4086{
4087 int i, ret = 0;
4088 struct ipa_sys_connect_params *ipa;
4089 uint32_t desc_fifo_sz;
4090
4091 /* The maximum number of descriptors that can be provided to a BAM at
4092 * once is one less than the total number of descriptors that the buffer
4093 * can contain.
4094 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4095 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4096 * be provided at once.
4097 * Because of above requirement, one extra descriptor will be added to
4098 * make sure hardware always has one descriptor.
4099 */
4100 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4101 + sizeof(struct sps_iovec);
4102
4103 /*setup TX pipes */
4104 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4105 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4106
4107 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4108 ipa->desc_fifo_sz = desc_fifo_sz;
4109 ipa->priv = &hdd_ipa->iface_context[i];
4110 ipa->notify = hdd_ipa_i2w_cb;
4111
4112 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4113 ipa->ipa_ep_cfg.hdr.hdr_len =
4114 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4115 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4116 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4117 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4118 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4119 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4120 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4121 } else {
4122 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4123 }
4124 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4125
4126 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4127 ipa->keep_ipa_awake = 1;
4128
4129 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4130 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304131 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004132 " ret: %d", i, ret);
4133 goto setup_sys_pipe_fail;
4134 }
4135 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4136 }
4137
4138 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4139 /*
4140 * Hard code it here, this can be extended if in case
4141 * PROD pipe is also per interface.
4142 * Right now there is no advantage of doing this.
4143 */
4144 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4145
4146 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4147
4148 ipa->client = hdd_ipa->prod_client;
4149
4150 ipa->desc_fifo_sz = desc_fifo_sz;
4151 ipa->priv = hdd_ipa;
4152 ipa->notify = hdd_ipa_w2i_cb;
4153
4154 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4155 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4156 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4157 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4158
4159 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4160 ipa->keep_ipa_awake = 1;
4161
4162 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4163 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304164 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004165 "Failed for RX pipe: %d", ret);
4166 goto setup_sys_pipe_fail;
4167 }
4168 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4169 }
4170
4171 return ret;
4172
4173setup_sys_pipe_fail:
4174
4175 while (--i >= 0) {
4176 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304177 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004178 sizeof(struct hdd_ipa_sys_pipe));
4179 }
4180
4181 return ret;
4182}
4183
4184/**
4185 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4186 * @hdd_ipa: Global HDD IPA context
4187 *
4188 * Return: None
4189 */
4190static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4191{
4192 int ret = 0, i;
4193 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4194 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4195 ret =
4196 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4197 conn_hdl);
4198 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304199 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004200 ret);
4201
4202 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4203 }
4204 }
4205}
4206
4207/**
4208 * hdd_ipa_register_interface() - register IPA interface
4209 * @hdd_ipa: Global IPA context
4210 * @iface_context: Per-interface IPA context
4211 *
4212 * Return: 0 on success, negative errno on error
4213 */
4214static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
4215 struct hdd_ipa_iface_context
4216 *iface_context)
4217{
4218 struct ipa_tx_intf tx_intf;
4219 struct ipa_rx_intf rx_intf;
4220 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
4221 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
4222 char *ifname = iface_context->adapter->dev->name;
4223
4224 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
4225 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
4226
4227 int num_prop = 1;
4228 int ret = 0;
4229
4230 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
4231 num_prop++;
4232
4233 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
4234 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304235 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004236 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304237 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004238 goto register_interface_fail;
4239 }
4240
4241 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
4242 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304243 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004244 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304245 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004246 goto register_interface_fail;
4247 }
4248
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304249 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
4250 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251
4252 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4253 ifname, HDD_IPA_IPV4_NAME_EXT);
4254 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4255 ifname, HDD_IPA_IPV6_NAME_EXT);
4256
4257 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4258 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
4259 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4260 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4261
4262 /*
4263 * Interface ID is 3rd byte in the CLD header. Add the meta data and
4264 * mask to identify the interface in IPA hardware
4265 */
4266 rx_prop[IPA_IP_v4].attrib.meta_data =
4267 htonl(iface_context->adapter->sessionId << 16);
4268 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4269
4270 rx_intf.num_props++;
4271 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4272 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4273 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
4274 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4275 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4276 rx_prop[IPA_IP_v4].attrib.meta_data =
4277 htonl(iface_context->adapter->sessionId << 16);
4278 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4279
4280 rx_intf.num_props++;
4281 }
4282
4283 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4284 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4285 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4286 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
4287 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
4288 IPA_RESOURCE_NAME_MAX);
4289 tx_intf.num_props++;
4290
4291 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4292 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4293 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4294 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4295 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
4296 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
4297 IPA_RESOURCE_NAME_MAX);
4298 tx_intf.num_props++;
4299 }
4300
4301 tx_intf.prop = tx_prop;
4302 rx_intf.prop = rx_prop;
4303
4304 /* Call the ipa api to register interface */
4305 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
4306
4307register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304308 qdf_mem_free(tx_prop);
4309 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004310 return ret;
4311}
4312
4313/**
4314 * hdd_remove_ipa_header() - Remove a specific header from IPA
4315 * @name: Name of the header to be removed
4316 *
4317 * Return: None
4318 */
4319static void hdd_ipa_remove_header(char *name)
4320{
4321 struct ipa_ioc_get_hdr hdrlookup;
4322 int ret = 0, len;
4323 struct ipa_ioc_del_hdr *ipa_hdr;
4324
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304325 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004326 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
4327 ret = ipa_get_hdr(&hdrlookup);
4328 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304329 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004330 name, ret);
4331 return;
4332 }
4333
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304334 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004335 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304336 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004337 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304338 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004339 return;
4340 }
4341 ipa_hdr->num_hdls = 1;
4342 ipa_hdr->commit = 0;
4343 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
4344 ipa_hdr->hdl[0].status = -1;
4345 ret = ipa_del_hdr(ipa_hdr);
4346 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304347 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004348 ret);
4349
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304350 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004351}
4352
4353/**
Yun Parkb187d542016-11-14 18:10:04 -08004354 * wlan_ipa_add_hdr() - Add IPA Tx header
4355 * @ipa_hdr: pointer to IPA header addition parameters
4356 *
4357 * Call IPA API to add IPA Tx header descriptor
4358 * and dump Tx header struct
4359 *
4360 * Return: 0 for success, non-zero for failure
4361 */
4362static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
4363{
4364 int ret;
4365
4366 hdd_info("==== IPA Tx Header ====\n"
4367 "name: %s\n"
4368 "hdr_len: %d\n"
4369 "type: %d\n"
4370 "is_partial: %d\n"
4371 "hdr_hdl: 0x%x\n"
4372 "status: %d\n"
4373 "is_eth2_ofst_valid: %d\n"
4374 "eth2_ofst: %d\n",
4375 ipa_hdr->hdr[0].name,
4376 ipa_hdr->hdr[0].hdr_len,
4377 ipa_hdr->hdr[0].type,
4378 ipa_hdr->hdr[0].is_partial,
4379 ipa_hdr->hdr[0].hdr_hdl,
4380 ipa_hdr->hdr[0].status,
4381 ipa_hdr->hdr[0].is_eth2_ofst_valid,
4382 ipa_hdr->hdr[0].eth2_ofst);
4383
4384 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:",
4385 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4386
4387 ret = ipa_add_hdr(ipa_hdr);
4388 return ret;
4389}
4390
4391/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004392 * hdd_ipa_add_header_info() - Add IPA header for a given interface
4393 * @hdd_ipa: Global HDD IPA context
4394 * @iface_context: Interface-specific HDD IPA context
4395 * @mac_addr: Interface MAC address
4396 *
4397 * Return: 0 on success, negativer errno value on error
4398 */
4399static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
4400 struct hdd_ipa_iface_context *iface_context,
4401 uint8_t *mac_addr)
4402{
4403 hdd_adapter_t *adapter = iface_context->adapter;
4404 char *ifname;
4405 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
4406 int ret = -EINVAL;
4407 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
4408 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
4409
4410 ifname = adapter->dev->name;
4411
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304412 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004413 ifname, mac_addr);
4414
4415 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304416 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417 + sizeof(struct ipa_hdr_add));
4418 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304419 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004420 "%s: ipa_hdr allocation failed", ifname);
4421 ret = -ENOMEM;
4422 goto end;
4423 }
4424
4425 ipa_hdr->commit = 0;
4426 ipa_hdr->num_hdrs = 1;
4427
4428 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4429 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4430 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4431 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4432 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304433 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004434 "ifname=%s, vdev_id=%d",
4435 ifname, uc_tx_hdr->ipa_hd.vdev_id);
4436 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4437 ifname, HDD_IPA_IPV4_NAME_EXT);
4438 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
4439 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
4440 ipa_hdr->hdr[0].is_partial = 1;
4441 ipa_hdr->hdr[0].hdr_hdl = 0;
4442 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4443 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4444
Yun Parkb187d542016-11-14 18:10:04 -08004445 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004446 } else {
4447 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4448
4449 /* Set the Source MAC */
4450 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
4451 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4452
4453 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4454 ifname, HDD_IPA_IPV4_NAME_EXT);
4455 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4456 ipa_hdr->hdr[0].is_partial = 1;
4457 ipa_hdr->hdr[0].hdr_hdl = 0;
4458 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4459 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4460
4461 /* Set the type to IPV4 in the header */
4462 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
4463
4464 ret = ipa_add_hdr(ipa_hdr);
4465 }
4466 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304467 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468 ifname, ret);
4469 goto end;
4470 }
4471
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304472 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004473 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4474
4475 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4476 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4477 ifname, HDD_IPA_IPV6_NAME_EXT);
4478
4479 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4480 uc_tx_hdr =
4481 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4482 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004483 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484 } else {
4485 /* Set the type to IPV6 in the header */
4486 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4487 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004488 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004489 }
4490
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004491 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304492 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004493 "%s: IPv6 add hdr failed: %d", ifname, ret);
4494 goto clean_ipv4_hdr;
4495 }
4496
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304497 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4499 }
4500
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304501 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502
4503 return ret;
4504
4505clean_ipv4_hdr:
4506 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4507 ifname, HDD_IPA_IPV4_NAME_EXT);
4508 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
4509end:
4510 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304511 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512
4513 return ret;
4514}
4515
4516/**
4517 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
4518 * @adapter: Adapter upon which IPA was previously configured
4519 *
4520 * Return: None
4521 */
4522static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
4523{
4524 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4525 int ret;
4526 char name_ipa[IPA_RESOURCE_NAME_MAX];
4527
4528 /* Remove the headers */
4529 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4530 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
4531 hdd_ipa_remove_header(name_ipa);
4532
4533 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4534 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4535 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
4536 hdd_ipa_remove_header(name_ipa);
4537 }
4538 /* unregister the interface with IPA */
4539 ret = ipa_deregister_intf(adapter->dev->name);
4540 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304541 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004542 "%s: ipa_deregister_intf fail: %d",
4543 adapter->dev->name, ret);
4544}
4545
4546/**
4547 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4548 * @iface_context: interface-specific IPA context
4549 *
4550 * Return: None
4551 */
4552static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4553{
4554 if (iface_context == NULL)
4555 return;
4556
4557 hdd_ipa_clean_hdr(iface_context->adapter);
4558
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304559 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004560 iface_context->adapter->ipa_context = NULL;
4561 iface_context->adapter = NULL;
4562 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304563 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004564 iface_context->ifa_address = 0;
4565 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304566 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004567 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304568 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004569 }
4570 iface_context->hdd_ipa->num_iface--;
4571}
4572
4573/**
4574 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4575 * @hdd_ipa: HDD IPA global context
4576 * @adapter: Interface upon which IPA is being setup
4577 * @sta_id: Station ID of the API instance
4578 *
4579 * Return: 0 on success, negative errno value on error
4580 */
4581static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
4582 hdd_adapter_t *adapter, uint8_t sta_id)
4583{
4584 struct hdd_ipa_iface_context *iface_context = NULL;
4585 void *tl_context = NULL;
4586 int i, ret = 0;
4587
4588 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4589 * channel change indication. Since these indications are sent by lower
4590 * layer as SAP updates and IPA doesn't have to do anything for these
4591 * updates so ignoring!
4592 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004593 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594 return 0;
4595
4596 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4597 if (hdd_ipa->iface_context[i].adapter == NULL) {
4598 iface_context = &(hdd_ipa->iface_context[i]);
4599 break;
4600 }
4601 }
4602
4603 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304604 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004605 "All the IPA interfaces are in use");
4606 ret = -ENOMEM;
4607 goto end;
4608 }
4609
4610 adapter->ipa_context = iface_context;
4611 iface_context->adapter = adapter;
4612 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004613 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07004614 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304616 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004617 "Not able to get TL context sta_id: %d", sta_id);
4618 ret = -EINVAL;
4619 goto end;
4620 }
4621
4622 iface_context->tl_context = tl_context;
4623
4624 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
4625 adapter->dev->dev_addr);
4626
4627 if (ret)
4628 goto end;
4629
4630 /* Configure the TX and RX pipes filter rules */
4631 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
4632 if (ret)
4633 goto cleanup_header;
4634
4635 hdd_ipa->num_iface++;
4636 return ret;
4637
4638cleanup_header:
4639
4640 hdd_ipa_clean_hdr(adapter);
4641end:
4642 if (iface_context)
4643 hdd_ipa_cleanup_iface(iface_context);
4644 return ret;
4645}
4646
Yun Parka27049a2016-10-11 12:30:49 -07004647#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004648/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004649 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004650 * @mcc_mode: 0=MCC/1=SCC
4651 *
4652 * Return: 0 on success, negative errno value on error
4653 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004654static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004655{
4656 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304657 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658 hdd_adapter_t *pAdapter;
4659 struct ipa_msg_meta meta;
4660 struct ipa_wlan_msg *msg;
4661 int ret;
4662
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004663 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004664 return -EINVAL;
4665
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004666 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4667 return -EINVAL;
4668
4669 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004670 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004671 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304672 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004673 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08004674 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004675 pAdapter->device_mode == QDF_SAP_MODE) {
4676 hdd_info("MCC->SCC: Flush TxRx queue(d_mode=%d)",
4677 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004678 hdd_deinit_tx_rx(pAdapter);
4679 }
4680 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004681 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004682 adapter_node = next;
4683 }
4684 }
4685
4686 /* Send SCC/MCC Switching event to IPA */
4687 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304688 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004689 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004690 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004691 return -ENOMEM;
4692 }
4693
4694 meta.msg_type = mcc_mode ?
4695 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004696 hdd_info("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004697
4698 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4699
4700 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004701 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004702 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304703 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004704 }
4705
4706 return ret;
4707}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004708
4709/**
4710 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4711 * @mcc_mode: 0=MCC/1=SCC
4712 *
4713 * Return: 0 on success, negative errno value on error
4714 */
4715int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
4716{
4717 int ret;
4718
4719 cds_ssr_protect(__func__);
4720 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4721 cds_ssr_unprotect(__func__);
4722
4723 return ret;
4724}
Yun Parka27049a2016-10-11 12:30:49 -07004725#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004726
4727/**
4728 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4729 * @event: IPA WLAN event to be converted to a string
4730 *
4731 * Return: ASCII string representing the IPA WLAN event
4732 */
4733static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4734{
4735 switch (event) {
4736 case WLAN_CLIENT_CONNECT:
4737 return "WLAN_CLIENT_CONNECT";
4738 case WLAN_CLIENT_DISCONNECT:
4739 return "WLAN_CLIENT_DISCONNECT";
4740 case WLAN_CLIENT_POWER_SAVE_MODE:
4741 return "WLAN_CLIENT_POWER_SAVE_MODE";
4742 case WLAN_CLIENT_NORMAL_MODE:
4743 return "WLAN_CLIENT_NORMAL_MODE";
4744 case SW_ROUTING_ENABLE:
4745 return "SW_ROUTING_ENABLE";
4746 case SW_ROUTING_DISABLE:
4747 return "SW_ROUTING_DISABLE";
4748 case WLAN_AP_CONNECT:
4749 return "WLAN_AP_CONNECT";
4750 case WLAN_AP_DISCONNECT:
4751 return "WLAN_AP_DISCONNECT";
4752 case WLAN_STA_CONNECT:
4753 return "WLAN_STA_CONNECT";
4754 case WLAN_STA_DISCONNECT:
4755 return "WLAN_STA_DISCONNECT";
4756 case WLAN_CLIENT_CONNECT_EX:
4757 return "WLAN_CLIENT_CONNECT_EX";
4758
4759 case IPA_WLAN_EVENT_MAX:
4760 default:
4761 return "UNKNOWN";
4762 }
4763}
4764
4765/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004766 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4767 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4768 *
4769 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4770 */
4771static enum ipa_wlan_event
4772hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4773{
4774 enum ipa_wlan_event ipa_event;
4775
4776 switch (hdd_ipa_event_type) {
4777 case HDD_IPA_CLIENT_CONNECT:
4778 ipa_event = WLAN_CLIENT_CONNECT;
4779 break;
4780 case HDD_IPA_CLIENT_DISCONNECT:
4781 ipa_event = WLAN_CLIENT_DISCONNECT;
4782 break;
4783 case HDD_IPA_AP_CONNECT:
4784 ipa_event = WLAN_AP_CONNECT;
4785 break;
4786 case HDD_IPA_AP_DISCONNECT:
4787 ipa_event = WLAN_AP_DISCONNECT;
4788 break;
4789 case HDD_IPA_STA_CONNECT:
4790 ipa_event = WLAN_STA_CONNECT;
4791 break;
4792 case HDD_IPA_STA_DISCONNECT:
4793 ipa_event = WLAN_STA_DISCONNECT;
4794 break;
4795 case HDD_IPA_CLIENT_CONNECT_EX:
4796 ipa_event = WLAN_CLIENT_CONNECT_EX;
4797 break;
4798 case HDD_IPA_WLAN_EVENT_MAX:
4799 default:
4800 ipa_event = IPA_WLAN_EVENT_MAX;
4801 break;
4802 }
4803 return ipa_event;
4804
4805}
4806
4807/**
4808 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004809 * @adapter: adapter upon which the event was received
4810 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004811 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004812 * @mac_address: MAC address associated with the event
4813 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004814 * This function is meant to be called from within wlan_hdd_ipa.c
4815 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004816 * Return: 0 on success, negative errno value on error
4817 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07004818static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004819 enum ipa_wlan_event type, uint8_t *mac_addr)
4820{
4821 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4822 struct ipa_msg_meta meta;
4823 struct ipa_wlan_msg *msg;
4824 struct ipa_wlan_msg_ex *msg_ex = NULL;
4825 int ret;
4826
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304827 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004828 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
4829 mac_addr, sta_id);
4830
4831 if (type >= IPA_WLAN_EVENT_MAX)
4832 return -EINVAL;
4833
4834 if (WARN_ON(is_zero_ether_addr(mac_addr)))
4835 return -EINVAL;
4836
4837 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304838 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004839 return -EINVAL;
4840 }
4841
4842 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
4843 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08004844 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004845 return 0;
4846 }
4847
4848 /*
4849 * During IPA UC resource loading/unloading new events can be issued.
4850 * Store the events separately and handle them later.
4851 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004852 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4853 if (hdd_ipa->resource_loading) {
4854 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004855 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08004856
Yun Park7c4f31b2016-11-30 10:09:21 -08004857 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA resource %s inprogress",
4858 hdd_ipa->resource_loading ? "load":"unload");
4859
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004860 hdd_err("IPA resource %s inprogress",
4861 hdd_ipa->resource_loading ? "load":"unload");
Yun Parkf19e07d2015-11-20 11:34:27 -08004862
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004863 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004864
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004865 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4866 if (pending_event_count >= HDD_IPA_MAX_PENDING_EVENT_COUNT) {
4867 hdd_notice("Reached max pending event count");
4868 qdf_list_remove_front(&hdd_ipa->pending_event,
4869 (qdf_list_node_t **)&pending_event);
4870 } else {
4871 pending_event =
4872 (struct ipa_uc_pending_event *)qdf_mem_malloc(
4873 sizeof(struct ipa_uc_pending_event));
4874 }
4875
4876 if (!pending_event) {
Yun Park7c4f31b2016-11-30 10:09:21 -08004877 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4878 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004879 qdf_mutex_release(&hdd_ipa->event_lock);
4880 return -ENOMEM;
4881 }
4882
4883 pending_event->adapter = adapter;
4884 pending_event->sta_id = sta_id;
4885 pending_event->type = type;
4886 qdf_mem_copy(pending_event->mac_addr,
4887 mac_addr,
4888 QDF_MAC_ADDR_SIZE);
4889 qdf_list_insert_back(&hdd_ipa->pending_event,
4890 &pending_event->node);
4891
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304892 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004893 return 0;
4894 } else if (hdd_ipa->resource_unloading) {
4895 hdd_err("%s: IPA resource unload inprogress", __func__);
4896 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004897 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004898 }
4899
4900 hdd_ipa->stats.event[type]++;
4901
Leo Chang3bc8fed2015-11-13 10:59:47 -08004902 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004903 switch (type) {
4904 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004905 qdf_mutex_acquire(&hdd_ipa->event_lock);
4906
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004907 /* STA already connected and without disconnect, connect again
4908 * This is Roaming scenario
4909 */
4910 if (hdd_ipa->sta_connected)
4911 hdd_ipa_cleanup_iface(adapter->ipa_context);
4912
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004913 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4914 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304915 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004916 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004917 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004918
Yun Park8f289c82016-10-18 16:38:21 -07004919 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4920 (hdd_ipa->sap_num_connected_sta > 0) &&
4921 !hdd_ipa->sta_connected) {
4922 qdf_mutex_release(&hdd_ipa->event_lock);
4923 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004924 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004925 qdf_mutex_acquire(&hdd_ipa->event_lock);
4926 }
4927
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004928 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004929 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004930 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004931
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004932 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07004933
4934 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004935 break;
4936
4937 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004938 qdf_mutex_acquire(&hdd_ipa->event_lock);
4939
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004940 /* For DFS channel we get two start_bss event (before and after
4941 * CAC). Also when ACS range includes both DFS and non DFS
4942 * channels, we could possibly change channel many times due to
4943 * RADAR detection and chosen channel may not be a DFS channels.
4944 * So dont return error here. Just discard the event.
4945 */
Yun Park8f289c82016-10-18 16:38:21 -07004946 if (adapter->ipa_context) {
4947 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004948 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07004949 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004950
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004951 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4952 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004953 hdd_err("%s: Evt: %d, Interface setup failed",
4954 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304955 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004956 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004957 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004958
Yun Park8f289c82016-10-18 16:38:21 -07004959 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4960 qdf_mutex_release(&hdd_ipa->event_lock);
4961 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004962 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004963 qdf_mutex_acquire(&hdd_ipa->event_lock);
4964 }
4965
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004966 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004967 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004968 (adapter->ipa_context))->iface_id;
4969
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304970 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004971 break;
4972
4973 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304974 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004975
4976 if (!hdd_ipa->sta_connected) {
Yun Parkb187d542016-11-14 18:10:04 -08004977 hdd_err("%s: Evt: %d, STA already disconnected",
4978 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304979 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004980 return -EINVAL;
4981 }
Yun Parka37592b2016-06-11 17:10:28 -07004982
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004983 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07004984
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004985 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08004986 hdd_notice("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004987 msg_ex->name);
4988 } else {
4989 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07004990 if (!hdd_ipa->num_iface &&
4991 (HDD_IPA_UC_NUM_WDI_PIPE ==
4992 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004993 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004994 }
4995
Yun Park74127cf2016-09-18 11:22:41 -07004996 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4997 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07004998 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005000 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005001 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005002 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5003 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005004 }
5005
Yun Park8f289c82016-10-18 16:38:21 -07005006 hdd_ipa_cleanup_iface(adapter->ipa_context);
5007
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305008 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005009 break;
5010
5011 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005012 qdf_mutex_acquire(&hdd_ipa->event_lock);
5013
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005014 if (!adapter->ipa_context) {
Yun Parkb187d542016-11-14 18:10:04 -08005015 hdd_err("%s: Evt: %d, SAP already disconnected",
5016 msg_ex->name, meta.msg_type);
Yun Park8f289c82016-10-18 16:38:21 -07005017 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005018 return -EINVAL;
5019 }
5020
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005021 if ((!hdd_ipa->num_iface) &&
5022 (HDD_IPA_UC_NUM_WDI_PIPE ==
5023 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005024 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005025 /*
5026 * We disable WDI pipes directly here since
5027 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5028 * processed when unloading WLAN driver is in
5029 * progress
5030 */
5031 hdd_ipa_uc_disable_pipes(hdd_ipa);
5032 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305033 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005034 "NO INTF left but still pipe clean up");
5035 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5036 }
5037 }
5038
5039 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005040 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005041 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005042 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005043 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005044 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5045 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005046 }
Yun Parka37592b2016-06-11 17:10:28 -07005047
Yun Park8f289c82016-10-18 16:38:21 -07005048 hdd_ipa_cleanup_iface(adapter->ipa_context);
5049
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305050 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005051 break;
5052
5053 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005054 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305055 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005056 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305057 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005058 return 0;
5059 }
5060
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305061 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005062 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5063 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005064 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305065 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005066 "%s: STA ID %d found, not valid",
5067 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005068 return 0;
5069 }
Yun Park312f71a2015-12-08 10:22:42 -08005070
5071 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005072 if (hdd_ipa->sap_num_connected_sta == 0 &&
5073 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005074 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005075 hdd_ipa->sta_connected) {
5076 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005077 hdd_ipa_uc_offload_enable_disable(
5078 hdd_get_adapter(hdd_ipa->hdd_ctx,
5079 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005080 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005081 qdf_mutex_acquire(&hdd_ipa->event_lock);
5082 }
Yun Parka37592b2016-06-11 17:10:28 -07005083
Yun Park312f71a2015-12-08 10:22:42 -08005084 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5085 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305086 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005087 "%s: handle 1st con ret %d",
5088 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005089
5090 if (hdd_ipa_uc_sta_is_enabled(
5091 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005092 hdd_ipa->sta_connected) {
5093 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005094 hdd_ipa_uc_offload_enable_disable(
5095 hdd_get_adapter(
5096 hdd_ipa->hdd_ctx,
5097 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005098 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005099 } else {
5100 qdf_mutex_release(&hdd_ipa->event_lock);
5101 }
Yun Parka37592b2016-06-11 17:10:28 -07005102
Yun Park312f71a2015-12-08 10:22:42 -08005103 return ret;
5104 }
5105 }
5106
5107 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005108
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305109 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005110
5111 meta.msg_type = type;
5112 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5113 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305114 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005115
5116 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305117 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005118 "msg_ex allocation failed");
5119 return -ENOMEM;
5120 }
5121 strlcpy(msg_ex->name, adapter->dev->name,
5122 IPA_RESOURCE_NAME_MAX);
5123 msg_ex->num_of_attribs = 1;
5124 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5125 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5126 msg_ex->attribs[0].offset =
5127 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5128 } else {
5129 msg_ex->attribs[0].offset =
5130 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5131 }
5132 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5133 IPA_MAC_ADDR_SIZE);
5134
5135 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5136
5137 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305138 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305139 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305140 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005141 return ret;
5142 }
5143 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005144 return ret;
5145
5146 case WLAN_CLIENT_DISCONNECT:
5147 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305148 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005149 "%s: IPA UC OFFLOAD NOT ENABLED",
5150 msg_ex->name);
5151 return 0;
5152 }
5153
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305154 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005155 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305156 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005157 "%s: STA ID %d NOT found, not valid",
5158 msg_ex->name, sta_id);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305159 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005160 return 0;
5161 }
5162 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005163
Yun Park9b5030f2016-11-08 12:02:37 -08005164 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005165 if (!hdd_ipa->sap_num_connected_sta &&
5166 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005167 if ((false == hdd_ipa->resource_unloading)
5168 && (HDD_IPA_UC_NUM_WDI_PIPE ==
5169 hdd_ipa->activated_fw_pipe)) {
5170 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5171 }
5172
Yun Park8f289c82016-10-18 16:38:21 -07005173 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005174
5175 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5176 hdd_ipa->sta_connected)
5177 hdd_ipa_uc_offload_enable_disable(
5178 hdd_get_adapter(hdd_ipa->hdd_ctx,
5179 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005180 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005181 } else {
5182 qdf_mutex_release(&hdd_ipa->event_lock);
5183 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005184 break;
5185
5186 default:
5187 return 0;
5188 }
5189
5190 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305191 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005192 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305193 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005194 return -ENOMEM;
5195 }
5196
5197 meta.msg_type = type;
5198 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5199 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5200
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305201 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005202 msg->name, meta.msg_type);
5203
5204 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5205
5206 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005207 hdd_err("%s: Evt: %d fail:%d",
5208 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305209 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005210 return ret;
5211 }
5212
5213 hdd_ipa->stats.num_send_msg++;
5214
5215end:
5216 return ret;
5217}
5218
5219/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005220 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005221 * @adapter: adapter upon which the event was received
5222 * @sta_id: station id for the event
5223 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5224 * @mac_address: MAC address associated with the event
5225 *
5226 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5227 *
5228 * Return: 0 on success, negative errno value on error
5229 */
5230int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
5231 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5232{
5233 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005234 int ret = 0;
5235
5236 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005237
Leo Changa202b522016-10-14 16:13:50 -07005238 /* Data path offload only support for STA and SAP mode */
5239 if ((QDF_STA_MODE == adapter->device_mode) ||
5240 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005241 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005242
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005243 cds_ssr_unprotect(__func__);
5244
5245 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005246}
5247
5248/**
5249 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5250 * @hdd_ipa: Global HDD IPA context
5251 *
5252 * Return: None
5253 */
5254static void
5255hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5256{
5257 unsigned int pending_event_count;
5258 struct ipa_uc_pending_event *pending_event = NULL;
5259
5260 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
5261 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
5262 "%s, Pending Event Count %d", __func__, pending_event_count);
5263 if (!pending_event_count) {
5264 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
5265 "%s, No Pending Event", __func__);
5266 return;
5267 }
5268
5269 qdf_list_remove_front(&hdd_ipa->pending_event,
5270 (qdf_list_node_t **)&pending_event);
5271 while (pending_event != NULL) {
5272 __hdd_ipa_wlan_evt(pending_event->adapter,
5273 pending_event->type,
5274 pending_event->sta_id,
5275 pending_event->mac_addr);
5276 qdf_mem_free(pending_event);
5277 pending_event = NULL;
5278 qdf_list_remove_front(&hdd_ipa->pending_event,
5279 (qdf_list_node_t **)&pending_event);
5280 }
5281}
5282
5283/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005284 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5285 * @state: IPA RM state value
5286 *
5287 * Return: ASCII string representing the IPA RM state
5288 */
5289static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5290{
5291 switch (state) {
5292 case HDD_IPA_RM_RELEASED:
5293 return "RELEASED";
5294 case HDD_IPA_RM_GRANT_PENDING:
5295 return "GRANT_PENDING";
5296 case HDD_IPA_RM_GRANTED:
5297 return "GRANTED";
5298 }
5299
5300 return "UNKNOWN";
5301}
5302
5303/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005304 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005305 * @hdd_ctx: HDD global context
5306 *
5307 * Allocate hdd_ipa resources, ipa pipe resource and register
5308 * wlan interface with IPA module.
5309 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305310 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005311 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005312static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005313{
5314 struct hdd_ipa_priv *hdd_ipa = NULL;
5315 int ret, i;
5316 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park7f171ab2016-07-29 15:44:22 -07005317 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005318
5319 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305320 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005321
Yun Park7f171ab2016-07-29 15:44:22 -07005322 if (!pdev) {
5323 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5324 goto fail_return;
5325 }
5326
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305327 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005328 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305329 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005330 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005331 }
5332
5333 hdd_ctx->hdd_ipa = hdd_ipa;
5334 ghdd_ipa = hdd_ipa;
5335 hdd_ipa->hdd_ctx = hdd_ctx;
5336 hdd_ipa->num_iface = 0;
5337
5338 /* Create the interface context */
5339 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5340 iface_context = &hdd_ipa->iface_context[i];
5341 iface_context->hdd_ipa = hdd_ipa;
5342 iface_context->cons_client =
5343 hdd_ipa_adapter_2_client[i].cons_client;
5344 iface_context->prod_client =
5345 hdd_ipa_adapter_2_client[i].prod_client;
5346 iface_context->iface_id = i;
5347 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305348 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005349 }
5350 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005351 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5352 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005353 }
5354
Leo Chang69c39692016-10-12 20:11:12 -07005355 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305356 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305357 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005358
5359 ret = hdd_ipa_setup_rm(hdd_ipa);
5360 if (ret)
5361 goto fail_setup_rm;
5362
5363 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5364 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305365 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005366 hdd_ipa->sap_num_connected_sta = 0;
5367 hdd_ipa->ipa_tx_packets_diff = 0;
5368 hdd_ipa->ipa_rx_packets_diff = 0;
5369 hdd_ipa->ipa_p_tx_packets = 0;
5370 hdd_ipa->ipa_p_rx_packets = 0;
5371 hdd_ipa->resource_loading = false;
5372 hdd_ipa->resource_unloading = false;
5373 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005374 hdd_ipa->ipa_pipes_down = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005375 /* Setup IPA sys_pipe for MCC */
5376 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5377 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5378 if (ret)
5379 goto fail_create_sys_pipe;
5380 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005381 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5382 goto fail_create_sys_pipe;
5383
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005384 } else {
5385 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5386 if (ret)
5387 goto fail_create_sys_pipe;
5388 }
5389
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305390 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005391
5392fail_create_sys_pipe:
5393 hdd_ipa_destroy_rm_resource(hdd_ipa);
5394fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305395 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305396 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005397 hdd_ctx->hdd_ipa = NULL;
5398 ghdd_ipa = NULL;
5399fail_return:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305400 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005401}
5402
5403/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005404 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5405 * @hdd_ctx: HDD global context
5406 *
5407 * Allocate hdd_ipa resources, ipa pipe resource and register
5408 * wlan interface with IPA module.
5409 *
5410 * Return: QDF_STATUS enumeration
5411 */
5412QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
5413{
5414 QDF_STATUS ret;
5415
5416 cds_ssr_protect(__func__);
5417 ret = __hdd_ipa_init(hdd_ctx);
5418 cds_ssr_unprotect(__func__);
5419
5420 return ret;
5421}
5422
Arun Khandavallicc544b32017-01-30 19:52:16 +05305423
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005424/**
Yun Parkf19e07d2015-11-20 11:34:27 -08005425 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
5426 * @hdd_ipa: pointer to HDD IPA struct
5427 *
5428 * Return: none
5429 */
Jeff Johnsond7720632016-10-05 16:04:32 -07005430static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08005431{
5432 struct ipa_uc_pending_event *pending_event = NULL;
5433
Anurag Chouhanffb21542016-02-17 14:33:03 +05305434 while (qdf_list_remove_front(&hdd_ipa->pending_event,
5435 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305436 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005437 }
5438
Anurag Chouhanffb21542016-02-17 14:33:03 +05305439 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005440}
5441
5442/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005443 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005444 * @hdd_ctx: HDD global context
5445 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305446 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005447 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005448static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005449{
5450 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5451 int i;
5452 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305453 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005454 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5455
5456 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305457 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005458
5459 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5460 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5461 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5462 }
5463
5464 /* Teardown IPA sys_pipe for MCC */
5465 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5466 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5467
5468 hdd_ipa_destroy_rm_resource(hdd_ipa);
5469
5470#ifdef WLAN_OPEN_SOURCE
5471 cancel_work_sync(&hdd_ipa->pm_work);
5472#endif
5473
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305474 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005475
Nirav Shahcbc6d722016-03-01 16:24:53 +05305476 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5477 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305478 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005479
5480 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
5481 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
5482
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305483 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005484 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305485 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005486
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305487 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005488
5489 /* destory the interface lock */
5490 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5491 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305492 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005493 }
5494
5495 /* This should never hit but still make sure that there are no pending
5496 * descriptor in IPA hardware
5497 */
5498 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305499 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005500 "IPA Pending write done: %d Waiting!",
5501 hdd_ipa->pending_hw_desc_cnt);
5502
5503 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
5504 usleep_range(100, 100);
5505 }
5506
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305507 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005508 "IPA Pending write done: desc: %d %s(%d)!",
5509 hdd_ipa->pending_hw_desc_cnt,
5510 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
5511 : "leak", i);
5512 }
5513 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08005514 if (ipa_uc_dereg_rdyCB())
5515 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5516 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005517 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005518 if (true == hdd_ipa->uc_loaded) {
5519 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305520 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
5521 __func__, hdd_ipa->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005522 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
5523 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305524 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
5525 __func__, hdd_ipa->rx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005526 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
5527 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305528 qdf_mutex_destroy(&hdd_ipa->event_lock);
5529 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005530 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005531
5532#ifdef WLAN_OPEN_SOURCE
5533 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5534 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5535 hdd_ipa->uc_op_work[i].msg = NULL;
5536 }
5537#endif
5538 }
5539
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305540 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005541 hdd_ctx->hdd_ipa = NULL;
5542
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305543 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005544}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005545
5546/**
5547 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5548 * @hdd_ctx: HDD global context
5549 *
5550 * Return: QDF_STATUS enumeration
5551 */
5552QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
5553{
5554 QDF_STATUS ret;
5555
5556 cds_ssr_protect(__func__);
5557 ret = __hdd_ipa_cleanup(hdd_ctx);
5558 cds_ssr_unprotect(__func__);
5559
5560 return ret;
5561}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005562#endif /* IPA_OFFLOAD */