blob: 76cb0a23136cdde97091adf5419011e142469c94 [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;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002326 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07002327 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08002328 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2329 int ret;
2330 QDF_STATUS stat = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002331
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002332 ENTER();
2333
Yun Parkbaa62862017-01-18 13:43:34 -08002334 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002335 if (!pdev || !soc) {
2336 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkbaa62862017-01-18 13:43:34 -08002337 stat = QDF_STATUS_E_FAILURE;
2338 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002339 }
Yun Parkbaa62862017-01-18 13:43:34 -08002340
2341 cdp_ipa_get_resource(soc, (void *)pdev, &ipa_ctxt->ipa_resource);
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08002342 if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) ||
2343 (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2344 (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2345 (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2346 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2347 "IPA UC resource alloc fail");
2348 return QDF_STATUS_E_FAILURE;
2349 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002350 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2351 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302352 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2353 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002354
Anurag Chouhanffb21542016-02-17 14:33:03 +05302355 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302356
2357 if (!cds_is_driver_recovering()) {
2358 qdf_mutex_create(&ipa_ctxt->event_lock);
2359 qdf_mutex_create(&ipa_ctxt->ipa_lock);
2360 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002361
2362 /* TX PIPE */
2363 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2364 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2365 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2366 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2367 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2368 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2369 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2370 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2371 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2372 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2373 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2374 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2375 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302376 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Parkbaa62862017-01-18 13:43:34 -08002377 "IPA RM DISABLED, IPA AWAKE");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002378 pipe_in.sys.keep_ipa_awake = true;
2379 }
2380
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002381 pipe_in.u.dl.comp_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002382 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002383 pipe_in.u.dl.comp_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002384 ipa_ctxt->ipa_resource.tx_comp_ring_size *
2385 sizeof(qdf_dma_addr_t);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002386 pipe_in.u.dl.ce_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002387 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002388 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
2389 pipe_in.u.dl.ce_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002390 ipa_ctxt->ipa_resource.ce_sr_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002391 pipe_in.u.dl.num_tx_buffers =
Yun Parkbaa62862017-01-18 13:43:34 -08002392 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002393
Yun Parkbaa62862017-01-18 13:43:34 -08002394 qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in,
2395 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002396 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08002397 IPA_CLIENT_WLAN1_CONS);
2398
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002399 if (true == ipa_ctxt->uc_loaded) {
2400 /* Connect WDI IPA PIPE */
Yun Parkbaa62862017-01-18 13:43:34 -08002401 ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2402 if (ret) {
2403 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2404 "ipa_connect_wdi_pipe falied for Tx: ret=%d",
2405 ret);
2406 stat = QDF_STATUS_E_FAILURE;
2407 goto fail_return;
2408 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002409 /* Micro Controller Doorbell register */
Yun Parkbaa62862017-01-18 13:43:34 -08002410 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2411 "CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
2412 (unsigned int)pipe_out.uc_door_bell_pa,
2413 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002414
2415 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Yun Parkbaa62862017-01-18 13:43:34 -08002416
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002417 /* WLAN TX PIPE Handle */
2418 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2419 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Yun Parkbaa62862017-01-18 13:43:34 -08002420 "TX : 0x%x, %d, 0x%x, 0x%x, %d, %d, 0x%x",
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002421 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
2422 pipe_in.u.dl.comp_ring_size,
2423 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
2424 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
2425 pipe_in.u.dl.ce_ring_size,
2426 pipe_in.u.dl.num_tx_buffers,
2427 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
2428 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002429
2430 /* RX PIPE */
2431 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2432 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
2433 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
2434 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
2435 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2436 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
2437 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
2438 sizeof(struct sps_iovec);
2439 pipe_in.sys.notify = hdd_ipa_w2i_cb;
2440 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302441 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkbaa62862017-01-18 13:43:34 -08002442 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002443 pipe_in.sys.keep_ipa_awake = true;
2444 }
2445
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002446 pipe_in.u.ul.rdy_ring_base_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002447 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002448 pipe_in.u.ul.rdy_ring_size =
Yun Parkbaa62862017-01-18 13:43:34 -08002449 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002450 pipe_in.u.ul.rdy_ring_rp_pa =
Yun Parkbaa62862017-01-18 13:43:34 -08002451 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002452 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Yun Parkbaa62862017-01-18 13:43:34 -08002453
2454 qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in,
2455 sizeof(struct ipa_wdi_in_params));
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002456 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
Yun Parkbaa62862017-01-18 13:43:34 -08002457 IPA_CLIENT_WLAN1_PROD);
2458
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002459 if (true == ipa_ctxt->uc_loaded) {
Yun Parkbaa62862017-01-18 13:43:34 -08002460 ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2461 if (ret) {
2462 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2463 "ipa_connect_wdi_pipe falied for Rx: ret=%d",
2464 ret);
2465 stat = QDF_STATUS_E_FAILURE;
2466 goto fail_return;
2467
2468 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002469 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2470 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Yun Parkbaa62862017-01-18 13:43:34 -08002471 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2472 "PROD DB pipe out 0x%x TX PIPE Handle 0x%x",
2473 (unsigned int)pipe_out.uc_door_bell_pa,
2474 ipa_ctxt->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002475 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2476 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
2477 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
2478 pipe_in.u.ul.rdy_ring_size,
2479 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
2480 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
2481 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002482
Yun Parkbaa62862017-01-18 13:43:34 -08002483 cdp_ipa_set_doorbell_paddr(soc, (void *)pdev,
2484 ipa_ctxt->tx_comp_doorbell_paddr,
2485 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002486
Yun Parkbaa62862017-01-18 13:43:34 -08002487 cdp_ipa_register_op_cb(soc, (void *)pdev,
2488 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
2489
2490 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2491 "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x",
2492 pdev->ipa_uc_op_cb,
2493 (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr,
2494 (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002495
2496 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08002497 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Yun Parkbaa62862017-01-18 13:43:34 -08002498 hdd_ipa_uc_fw_op_event_handler);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002499 ipa_ctxt->uc_op_work[i].msg = NULL;
2500 }
2501
Yun Parkbaa62862017-01-18 13:43:34 -08002502fail_return:
2503 EXIT();
2504 return stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002505}
2506
Leo Change3e49442015-10-26 20:07:13 -07002507/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002508 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002509 * @hdd_ctx: hdd main context
2510 *
2511 * Force shutdown IPA pipe
2512 * Independent of FW pipe status, IPA pipe shutdonw progress
2513 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2514 * independent from FW pipe status
2515 *
2516 * Return: NONE
2517 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002518static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002519{
2520 struct hdd_ipa_priv *hdd_ipa;
2521
2522 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2523 return;
2524
2525 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2526 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302527 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07002528 "IPA pipes are not down yet, force shutdown");
2529 hdd_ipa_uc_disable_pipes(hdd_ipa);
2530 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302531 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Leo Change3e49442015-10-26 20:07:13 -07002532 "IPA pipes are down, do nothing");
2533 }
2534
2535 return;
2536}
2537
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002538/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002539 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2540 * __hdd_ipa_uc_force_pipe_shutdown
2541 * @hdd_ctx: hdd main context
2542 *
2543 * Force shutdown IPA pipe
2544 * Independent of FW pipe status, IPA pipe shutdonw progress
2545 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2546 * independent from FW pipe status
2547 *
2548 * Return: NONE
2549 */
2550void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2551{
2552 cds_ssr_protect(__func__);
2553 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2554 cds_ssr_unprotect(__func__);
2555}
2556
2557/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302558 * hdd_ipa_msg_free_fn() - Free an IPA message
2559 * @buff: pointer to the IPA message
2560 * @len: length of the IPA message
2561 * @type: type of IPA message
2562 *
2563 * Return: None
2564 */
2565static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2566{
2567 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "msg type:%d, len:%d", type, len);
2568 ghdd_ipa->stats.num_free_msg++;
2569 qdf_mem_free(buff);
2570}
2571
Govind Singh9c58eba2016-09-02 16:23:06 +05302572/**
jge62037862016-12-09 10:44:33 +08002573 * hdd_ipa_uc_send_evt() - send event to ipa
2574 * @hdd_ctx: pointer to hdd context
2575 * @type: event type
2576 * @mac_addr: pointer to mac address
2577 *
2578 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05302579 *
2580 * Return: 0 - Success
2581 */
jge62037862016-12-09 10:44:33 +08002582static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
2583 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05302584{
jge62037862016-12-09 10:44:33 +08002585 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05302586 struct ipa_msg_meta meta;
2587 struct ipa_wlan_msg *msg;
2588 int ret = 0;
jge62037862016-12-09 10:44:33 +08002589
2590 meta.msg_len = sizeof(struct ipa_wlan_msg);
2591 msg = qdf_mem_malloc(meta.msg_len);
2592 if (msg == NULL) {
2593 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2594 "msg allocation failed");
2595 return -ENOMEM;
2596 }
2597
2598 meta.msg_type = type;
2599 strlcpy(msg->name, adapter->dev->name,
2600 IPA_RESOURCE_NAME_MAX);
2601 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
2602 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
2603 msg->name, meta.msg_type);
2604 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2605 if (ret) {
2606 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2607 "%s: Evt: %d fail:%d",
2608 msg->name, meta.msg_type, ret);
2609 qdf_mem_free(msg);
2610 return ret;
2611 }
2612
2613 hdd_ipa->stats.num_send_msg++;
2614
2615 return ret;
2616}
2617
2618/**
2619 * hdd_ipa_uc_disconnect_client() - send client disconnect event
2620 * @hdd_ctx: pointer to hdd adapter
2621 *
2622 * Send disconnect client event to IPA driver during SSR
2623 *
2624 * Return: 0 - Success
2625 */
2626static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
2627{
2628 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2629 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05302630 int i;
2631
2632 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2633 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2634 continue;
2635 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08002636 (!adapter->aStaInfo[i].isDeauthInProgress) &&
2637 hdd_ipa->sap_num_connected_sta) {
2638 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
2639 adapter->aStaInfo[i].macAddrSTA.bytes);
2640 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05302641 }
2642 }
2643
2644 return ret;
2645}
2646
2647/**
jge62037862016-12-09 10:44:33 +08002648 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
2649 * @hdd_ctx: pointer to hdd adapter
2650 *
2651 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05302652 *
2653 * Return: 0 - Success
2654 */
jge62037862016-12-09 10:44:33 +08002655
2656static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
2657{
2658 int ret = 0;
2659
2660 if (adapter->ipa_context)
2661 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
2662 adapter->dev->dev_addr);
2663
2664 return ret;
2665}
2666
2667#ifdef IPA_UC_STA_OFFLOAD
2668/**
2669 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
2670 * @hdd_ctx: pointer to hdd adapter
2671 *
2672 * Send disconnect sta event to IPA driver during SSR
2673 *
2674 * Return: 0 - Success
2675 */
2676static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2677{
2678 hdd_station_ctx_t *pHddStaCtx;
2679 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2680 int ret = 0;
2681
2682 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa) &&
2683 hdd_ipa->sta_connected) {
2684 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2685 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
2686 pHddStaCtx->conn_info.bssId);
2687 }
2688
2689 return ret;
2690}
2691#else
2692static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2693{
2694 return 0;
2695}
2696
2697#endif
2698
2699/**
2700 * hdd_ipa_uc_disconnect() - send disconnect ipa event
2701 * @hdd_ctx: pointer to hdd context
2702 *
2703 * Send disconnect event to IPA driver during SSR
2704 *
2705 * Return: 0 - Success
2706 */
2707static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05302708{
2709 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2710 QDF_STATUS status;
2711 hdd_adapter_t *adapter;
2712 int ret = 0;
2713
Govind Singh9c58eba2016-09-02 16:23:06 +05302714 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2715 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2716 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08002717 if (adapter->device_mode == QDF_SAP_MODE) {
2718 hdd_ipa_uc_disconnect_client(adapter);
2719 hdd_ipa_uc_disconnect_ap(adapter);
2720 } else if (adapter->device_mode == QDF_STA_MODE) {
2721 hdd_ipa_uc_disconnect_sta(adapter);
2722 }
2723
Govind Singh9c58eba2016-09-02 16:23:06 +05302724 status = hdd_get_next_adapter(
2725 hdd_ctx, adapter_node, &next);
2726 adapter_node = next;
2727 }
2728
2729 return ret;
2730}
2731
2732/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002733 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002734 *
2735 * Deinit basic IPA UC host side to be in sync reloaded FW during
2736 * SSR
2737 *
2738 * Return: 0 - Success
2739 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002740static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002741{
2742 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2743 int idx;
2744 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302745 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002746
Arun Khandavallicc544b32017-01-30 19:52:16 +05302747 if (!hdd_ipa)
2748 return 0;
2749
2750 hdd_ctx = hdd_ipa->hdd_ctx;
2751 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002752 return 0;
2753
jge62037862016-12-09 10:44:33 +08002754 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302755 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08002756
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002757 /* Clean up HDD IPA interfaces */
2758 for (idx = 0; (hdd_ipa->num_iface > 0) &&
2759 (idx < HDD_IPA_MAX_IFACE); idx++) {
2760 iface_context = &hdd_ipa->iface_context[idx];
2761 if (iface_context && iface_context->adapter)
2762 hdd_ipa_cleanup_iface(iface_context);
2763 }
2764
2765 /* After SSR, wlan driver reloads FW again. But we need to protect
2766 * IPA submodule during SSR transient state. So deinit basic IPA
2767 * UC host side to be in sync with reloaded FW during SSR
2768 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08002769 if (!hdd_ipa->ipa_pipes_down)
2770 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002771
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302772 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002773 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2774 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
2775 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
2776 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302777 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002778
Arun Khandavallicc544b32017-01-30 19:52:16 +05302779 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2780 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
2781 __func__, hdd_ipa->tx_pipe_handle);
2782 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
2783
2784 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2785 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
2786 __func__, hdd_ipa->rx_pipe_handle);
2787 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
2788
Guolei Bianca144d82016-11-10 11:07:42 +08002789 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
2790 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
2791
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002792 /* Full IPA driver cleanup not required since wlan driver is now
2793 * unloaded and reloaded after SSR.
2794 */
2795 return 0;
2796}
2797
2798/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002799 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
2800 *
2801 * Deinit basic IPA UC host side to be in sync reloaded FW during
2802 * SSR
2803 *
2804 * Return: 0 - Success
2805 */
2806int hdd_ipa_uc_ssr_deinit(void)
2807{
2808 int ret;
2809
2810 cds_ssr_protect(__func__);
2811 ret = __hdd_ipa_uc_ssr_deinit();
2812 cds_ssr_unprotect(__func__);
2813
2814 return ret;
2815}
2816
2817/**
2818 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002819 *
2820 * Init basic IPA UC host side to be in sync with reloaded FW after
2821 * SSR to resume IPA UC operations
2822 *
2823 * Return: 0 - Success
2824 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302825static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002826{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002827
Arun Khandavallicc544b32017-01-30 19:52:16 +05302828 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2829 int i;
2830 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302831
2832 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
2833 return 0;
2834
Arun Khandavallicc544b32017-01-30 19:52:16 +05302835 /* Create the interface context */
2836 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2837 iface_context = &hdd_ipa->iface_context[i];
2838 iface_context->hdd_ipa = hdd_ipa;
2839 iface_context->cons_client =
2840 hdd_ipa_adapter_2_client[i].cons_client;
2841 iface_context->prod_client =
2842 hdd_ipa_adapter_2_client[i].prod_client;
2843 iface_context->iface_id = i;
2844 iface_context->adapter = NULL;
2845 }
2846 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
2847 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
2848 hdd_ipa->vdev_offload_enabled[i] = false;
2849 }
2850
2851 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2852 hdd_ipa->resource_loading = false;
2853 hdd_ipa->resource_unloading = false;
2854 hdd_ipa->sta_connected = 0;
2855 hdd_ipa->ipa_pipes_down = true;
2856 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302857 }
2858
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002859 return 0;
2860}
Leo Chang3bc8fed2015-11-13 10:59:47 -08002861
2862/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002863 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
2864 *
2865 * Init basic IPA UC host side to be in sync with reloaded FW after
2866 * SSR to resume IPA UC operations
2867 *
2868 * Return: 0 - Success
2869 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302870int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002871{
2872 int ret;
2873
2874 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302875 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002876 cds_ssr_unprotect(__func__);
2877
2878 return ret;
2879}
2880
2881/**
2882 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08002883 * @hdd_ctx: Global HDD context
2884 * @skb: skb sent to IPA
2885 * @session_id: send packet instance session id
2886 *
2887 * Send TX packet which generated by system to IPA.
2888 * This routine only will be used for function verification
2889 *
2890 * Return: NULL packet sent to IPA properly
2891 * NULL invalid packet drop
2892 * skb packet not sent to IPA. legacy data path should handle
2893 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002894static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002895 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07002896{
Leo Chang3bc8fed2015-11-13 10:59:47 -08002897 struct ipa_header *ipa_header;
2898 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002899 struct hdd_ipa_priv *hdd_ipa;
2900
2901 if (wlan_hdd_validate_context(hdd_ctx))
2902 return skb;
2903
2904 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002905
2906 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2907 return skb;
2908
Leo Chang07b28f62016-05-11 12:29:22 -07002909 if (!hdd_ipa)
2910 return skb;
2911
2912 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
2913 return skb;
2914
Leo Changcc923e22016-06-16 15:29:03 -07002915 if (skb_headroom(skb) <
2916 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07002917 return skb;
2918
Leo Chang3bc8fed2015-11-13 10:59:47 -08002919 ipa_header = (struct ipa_header *) skb_push(skb,
2920 sizeof(struct ipa_header));
2921 if (!ipa_header) {
2922 /* No headroom, legacy */
2923 return skb;
2924 }
2925 memset(ipa_header, 0, sizeof(*ipa_header));
2926 ipa_header->vdev_id = 0;
2927
2928 frag_header = (struct frag_header *) skb_push(skb,
2929 sizeof(struct frag_header));
2930 if (!frag_header) {
2931 /* No headroom, drop */
2932 kfree_skb(skb);
2933 return NULL;
2934 }
2935 memset(frag_header, 0, sizeof(*frag_header));
2936 frag_header->length = skb->len - sizeof(struct frag_header)
2937 - sizeof(struct ipa_header);
2938
2939 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
2940 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07002941}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002942
2943/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002944 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
2945 * @hdd_ctx: Global HDD context
2946 * @skb: skb sent to IPA
2947 * @session_id: send packet instance session id
2948 *
2949 * Send TX packet which generated by system to IPA.
2950 * This routine only will be used for function verification
2951 *
2952 * Return: NULL packet sent to IPA properly
2953 * NULL invalid packet drop
2954 * skb packet not sent to IPA. legacy data path should handle
2955 */
2956struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
2957 struct sk_buff *skb, uint8_t session_id)
2958{
2959 struct sk_buff *ret;
2960
2961 cds_ssr_protect(__func__);
2962 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
2963 cds_ssr_unprotect(__func__);
2964
2965 return ret;
2966}
2967
2968/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002969 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
2970 * @work: scheduled work
2971 *
2972 * When IPA resources are released in hdd_ipa_rm_try_release() we do
2973 * not want to immediately release the wake lock since the system
2974 * would then potentially try to suspend when there is a healthy data
2975 * rate. Deferred work is scheduled and this function handles the
2976 * work. When this function is called, if the IPA resource is still
2977 * released then we release the wake lock.
2978 *
2979 * Return: None
2980 */
2981static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
2982{
2983 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
2984 struct hdd_ipa_priv,
2985 wake_lock_work);
2986
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302987 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002988
2989 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
2990 goto end;
2991
2992 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302993 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002994 WIFI_POWER_EVENT_WAKELOCK_IPA);
2995
2996end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302997 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002998}
2999
3000/**
3001 * hdd_ipa_rm_request() - Request resource from IPA
3002 * @hdd_ipa: Global HDD IPA context
3003 *
3004 * Return: 0 on success, negative errno on error
3005 */
3006static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3007{
3008 int ret = 0;
3009
3010 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3011 return 0;
3012
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303013 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003014
3015 switch (hdd_ipa->rm_state) {
3016 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303017 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 return 0;
3019 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303020 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003021 return -EINPROGRESS;
3022 case HDD_IPA_RM_RELEASED:
3023 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3024 break;
3025 }
3026
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303027 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003028
3029 ret = ipa_rm_inactivity_timer_request_resource(
3030 IPA_RM_RESOURCE_WLAN_PROD);
3031
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303032 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003033 if (ret == 0) {
3034 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3035 hdd_ipa->stats.num_rm_grant_imm++;
3036 }
3037
3038 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3039 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303040 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003041 WIFI_POWER_EVENT_WAKELOCK_IPA);
3042 hdd_ipa->wake_lock_released = false;
3043 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303044 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003045
3046 return ret;
3047}
3048
3049/**
3050 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3051 * @hdd_ipa: Global HDD IPA context
3052 *
3053 * Return: 0 if resources released, negative errno otherwise
3054 */
3055static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3056{
3057 int ret = 0;
3058
3059 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3060 return 0;
3061
3062 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3063 return -EAGAIN;
3064
3065 spin_lock_bh(&hdd_ipa->q_lock);
3066 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
3067 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
3068 spin_unlock_bh(&hdd_ipa->q_lock);
3069 return -EAGAIN;
3070 }
3071 spin_unlock_bh(&hdd_ipa->q_lock);
3072
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303073 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003074
Nirav Shahcbc6d722016-03-01 16:24:53 +05303075 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303076 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003077 return -EAGAIN;
3078 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303079 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003080
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303081 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003082 switch (hdd_ipa->rm_state) {
3083 case HDD_IPA_RM_GRANTED:
3084 break;
3085 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303086 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003087 return -EINPROGRESS;
3088 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303089 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003090 return 0;
3091 }
3092
3093 /* IPA driver returns immediately so set the state here to avoid any
3094 * race condition.
3095 */
3096 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3097 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303098 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003099
3100 ret =
3101 ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
3102
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303103 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003104 if (unlikely(ret != 0)) {
3105 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3106 WARN_ON(1);
3107 }
3108
3109 /*
3110 * If wake_lock is released immediately, kernel would try to suspend
3111 * immediately as well, Just avoid ping-pong between suspend-resume
3112 * while there is healthy amount of data transfer going on by
3113 * releasing the wake_lock after some delay.
3114 */
3115 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3116 msecs_to_jiffies
3117 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3118
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303119 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003120
3121 return ret;
3122}
3123
3124/**
3125 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3126 * @user_data: user data registered with IPA
3127 * @event: the IPA resource manager event that occurred
3128 * @data: the data associated with the event
3129 *
3130 * Return: None
3131 */
3132static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3133 unsigned long data)
3134{
3135 struct hdd_ipa_priv *hdd_ipa = user_data;
3136
3137 if (unlikely(!hdd_ipa))
3138 return;
3139
3140 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3141 return;
3142
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303143 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003144
3145 switch (event) {
3146 case IPA_RM_RESOURCE_GRANTED:
3147 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3148 /* RM Notification comes with ISR context
3149 * it should be serialized into work queue to avoid
3150 * ISR sleep problem
3151 */
3152 hdd_ipa->uc_rm_work.event = event;
3153 schedule_work(&hdd_ipa->uc_rm_work.work);
3154 break;
3155 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303156 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003157 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303158 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003159 hdd_ipa->stats.num_rm_grant++;
3160 break;
3161
3162 case IPA_RM_RESOURCE_RELEASED:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303163 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003164 hdd_ipa->resource_unloading = false;
3165 break;
3166
3167 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303168 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003169 break;
3170 }
3171}
3172
3173/**
3174 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3175 *
3176 * Callback function registered with IPA that is called when IPA wants
3177 * to release the WLAN consumer resource
3178 *
3179 * Return: 0 if the request is granted, negative errno otherwise
3180 */
3181static int hdd_ipa_rm_cons_release(void)
3182{
3183 return 0;
3184}
3185
3186/**
3187 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3188 *
3189 * Callback function registered with IPA that is called when IPA wants
3190 * to access the WLAN consumer resource
3191 *
3192 * Return: 0 if the request is granted, negative errno otherwise
3193 */
3194static int hdd_ipa_rm_cons_request(void)
3195{
Yun Park4d8b60a2015-10-22 13:59:32 -07003196 int ret = 0;
3197
3198 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303199 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003200 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003201 __func__);
3202 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003203 ret = -EINPROGRESS;
3204 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303205 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003206 "%s: IPA resource unloading in progress",
3207 __func__);
3208 ghdd_ipa->pending_cons_req = true;
3209 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003210 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003211
3212 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003213}
3214
3215/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003216 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003217 * @hdd_ctx: Global HDD context
3218 * @tx_packets: Number of packets transmitted in the last sample period
3219 * @rx_packets: Number of packets received in the last sample period
3220 *
3221 * Return: 0 on success, negative errno on error
3222 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003223static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003224 uint64_t rx_packets)
3225{
3226 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003227 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003228 struct ipa_rm_perf_profile profile;
3229 int ret;
3230
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003231 if (wlan_hdd_validate_context(hdd_ctx))
3232 return 0;
3233
3234 hdd_ipa = hdd_ctx->hdd_ipa;
3235
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003236 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3237 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3238 return 0;
3239
3240 memset(&profile, 0, sizeof(profile));
3241
3242 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3243 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3244 else if (tx_packets >
3245 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3246 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3247 else
3248 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3249
3250 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3251 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3252 else if (rx_packets >
3253 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3254 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3255 else
3256 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3257
Yun Park8f289c82016-10-18 16:38:21 -07003258 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003259 "CONS perf curr: %d, next: %d",
3260 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Park8f289c82016-10-18 16:38:21 -07003261 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003262 "PROD perf curr: %d, next: %d",
3263 hdd_ipa->curr_prod_bw, next_prod_bw);
3264
3265 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003266 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003267 hdd_ipa->curr_cons_bw, next_cons_bw);
3268 profile.max_supported_bandwidth_mbps = next_cons_bw;
3269 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3270 &profile);
3271 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003272 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003273
3274 return ret;
3275 }
3276 hdd_ipa->curr_cons_bw = next_cons_bw;
3277 hdd_ipa->stats.num_cons_perf_req++;
3278 }
3279
3280 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003281 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003282 hdd_ipa->curr_prod_bw, next_prod_bw);
3283 profile.max_supported_bandwidth_mbps = next_prod_bw;
3284 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3285 &profile);
3286 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003287 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003288 return ret;
3289 }
3290 hdd_ipa->curr_prod_bw = next_prod_bw;
3291 hdd_ipa->stats.num_prod_perf_req++;
3292 }
3293
3294 return 0;
3295}
3296
3297/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003298 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3299 * @hdd_ctx: Global HDD context
3300 * @tx_packets: Number of packets transmitted in the last sample period
3301 * @rx_packets: Number of packets received in the last sample period
3302 *
3303 * Return: 0 on success, negative errno on error
3304 */
3305int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3306 uint64_t rx_packets)
3307{
3308 int ret;
3309
3310 cds_ssr_protect(__func__);
3311 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3312 cds_ssr_unprotect(__func__);
3313
3314 return ret;
3315}
3316
3317/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003318 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3319 * @work: struct work_struct
3320 * @work_handler: work_handler
3321 *
3322 * Return: none
3323 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003324static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3325 work_func_t work_handler)
3326{
3327 INIT_WORK(work, work_handler);
3328}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003329
3330/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003331 * hdd_ipa_setup_rm() - Setup IPA resource management
3332 * @hdd_ipa: Global HDD IPA context
3333 *
3334 * Return: 0 on success, negative errno on error
3335 */
3336static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3337{
3338 struct ipa_rm_create_params create_params = { 0 };
3339 int ret;
3340
3341 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3342 return 0;
3343
Rajeev Kumar217f2172016-01-06 18:11:55 -08003344 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3345 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003346 memset(&create_params, 0, sizeof(create_params));
3347 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3348 create_params.reg_params.user_data = hdd_ipa;
3349 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3350 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3351
3352 ret = ipa_rm_create_resource(&create_params);
3353 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303354 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003355 "Create RM resource failed: %d", ret);
3356 goto setup_rm_fail;
3357 }
3358
3359 memset(&create_params, 0, sizeof(create_params));
3360 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3361 create_params.request_resource = hdd_ipa_rm_cons_request;
3362 create_params.release_resource = hdd_ipa_rm_cons_release;
3363 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3364
3365 ret = ipa_rm_create_resource(&create_params);
3366 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303367 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003368 "Create RM CONS resource failed: %d", ret);
3369 goto delete_prod;
3370 }
3371
3372 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3373 IPA_RM_RESOURCE_APPS_CONS);
3374
3375 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3376 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3377 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303378 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003379 ret);
3380 goto timer_init_failed;
3381 }
3382
3383 /* Set the lowest bandwidth to start with */
3384 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3385
3386 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303387 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003388 "Set perf level failed: %d", ret);
3389 goto set_perf_failed;
3390 }
3391
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303392 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003393 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3394 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303395 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003396 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3397 hdd_ipa->wake_lock_released = true;
3398 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3399
3400 return ret;
3401
3402set_perf_failed:
3403 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3404
3405timer_init_failed:
3406 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3407
3408delete_prod:
3409 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3410
3411setup_rm_fail:
3412 return ret;
3413}
3414
3415/**
3416 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3417 * @hdd_ipa: Global HDD IPA context
3418 *
3419 * Destroys all resources associated with the IPA resource manager
3420 *
3421 * Return: None
3422 */
3423static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3424{
3425 int ret;
3426
3427 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3428 return;
3429
3430 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303431 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003432
3433#ifdef WLAN_OPEN_SOURCE
3434 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
3435#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303436 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003437
3438 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3439
3440 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3441 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303442 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003443 "RM PROD resource delete failed %d", ret);
3444
3445 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3446 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303447 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003448 "RM CONS resource delete failed %d", ret);
3449}
3450
3451/**
3452 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3453 * @skb: network buffer
3454 * @adapter: network adapter
3455 *
3456 * Called when a network buffer is received which should not be routed
3457 * to the IPA module.
3458 *
3459 * Return: None
3460 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303461static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003462 hdd_adapter_t *adapter)
3463{
3464 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3465 unsigned int cpu_index;
3466
3467 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303468 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003469 adapter);
3470 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003471 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003472 return;
3473 }
3474
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003475 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003476 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003477 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003478 return;
3479 }
3480
3481 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3482 skb->dev = adapter->dev;
3483 skb->protocol = eth_type_trans(skb, skb->dev);
3484 skb->ip_summed = CHECKSUM_NONE;
3485
3486 cpu_index = wlan_hdd_get_cpu();
3487
3488 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
3489 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
3490 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3491 else
3492 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3493
3494 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
3495 adapter->dev->last_rx = jiffies;
3496}
3497
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003498/**
Leo Chang69c39692016-10-12 20:11:12 -07003499 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3500 * @hdd_ipa: pointer to hdd ipa context
3501 * @adapter: network adapter
3502 * @skb: data pointer
3503 *
3504 * if exception packet has set forward bit, copied new packet should be
3505 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3506 * put into pm queue and tx procedure will be differed
3507 *
3508 * Return: None
3509 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003510static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
3511 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003512{
Leo Chang69c39692016-10-12 20:11:12 -07003513 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3514
Leo Chang69c39692016-10-12 20:11:12 -07003515 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
3516 /* WLAN subsystem is in suspend, put int queue */
3517 if (hdd_ipa->suspended) {
3518 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3519 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3520 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003521 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3522 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003523 pm_tx_cb->exception = true;
3524 pm_tx_cb->adapter = adapter;
3525 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003526 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003527 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3528 hdd_ipa->stats.num_tx_queued++;
3529 } else {
3530 /* Resume, put packet into WLAN TX */
3531 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003532 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003533 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3534 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003535 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003536 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003537 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003538 hdd_ipa->ipa_tx_forward++;
3539 }
3540 }
3541}
3542
3543/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003544 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3545 * @hdd_ipa: pointer to HDD IPA struct
3546 * @adapter: hdd adapter pointer
3547 * @desc: Firmware descriptor
3548 * @skb: Data buffer
3549 *
3550 * Return:
3551 * HDD_IPA_FORWARD_PKT_NONE
3552 * HDD_IPA_FORWARD_PKT_DISCARD
3553 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3554 *
3555 */
3556
3557static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3558 struct hdd_ipa_priv *hdd_ipa,
3559 hdd_adapter_t *adapter,
3560 uint8_t desc,
3561 qdf_nbuf_t skb)
3562{
3563 int ret = HDD_IPA_FORWARD_PKT_NONE;
3564
3565 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303566 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003567 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
3568 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303569 /* Drop the packet*/
3570 hdd_ipa->stats.num_tx_fwd_err++;
3571 kfree_skb(skb);
3572 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3573 return ret;
3574 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003575 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3576 "Forward packet to Tx (fw_desc=%d)", desc);
3577 hdd_ipa->ipa_tx_forward++;
3578
3579 if ((desc & FW_RX_DESC_DISCARD_M)) {
3580 hdd_ipa_forward(hdd_ipa, adapter, skb);
3581 hdd_ipa->ipa_rx_internel_drop_count++;
3582 hdd_ipa->ipa_rx_discard++;
3583 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3584 } else {
3585 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
3586 if (cloned_skb)
3587 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3588 else
3589 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3590 "%s: tx skb alloc failed",
3591 __func__);
3592 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3593 }
3594 }
3595
3596 return ret;
3597}
3598
3599/**
Leo Chang69c39692016-10-12 20:11:12 -07003600 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003601 * @priv: pointer to private data registered with IPA (we register a
3602 * pointer to the global IPA context)
3603 * @evt: the IPA event which triggered the callback
3604 * @data: data associated with the event
3605 *
3606 * Return: None
3607 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003608static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003609 unsigned long data)
3610{
3611 struct hdd_ipa_priv *hdd_ipa = NULL;
3612 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303613 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003614 uint8_t iface_id;
3615 uint8_t session_id;
3616 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003617 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003618 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003619
3620 hdd_ipa = (struct hdd_ipa_priv *)priv;
3621
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003622 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3623 return;
3624
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003625 switch (evt) {
3626 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303627 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003628
3629 /*
3630 * When SSR is going on or driver is unloading,
3631 * just drop the packets.
3632 */
3633 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
3634 if (0 != status) {
3635 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3636 "Invalid context: drop packet");
3637 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3638 kfree_skb(skb);
3639 return;
3640 }
3641
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003642 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3643 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003644 iface_id = hdd_ipa->vdev_to_iface[session_id];
Govind Singhb6a89772016-08-12 11:23:35 +05303645 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003646 "IPA_RECEIVE: session_id=%u, iface_id=%u",
3647 session_id, iface_id);
3648 } else {
3649 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
3650 }
3651
3652 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303653 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003654 "IPA_RECEIVE: Invalid iface_id: %u",
3655 iface_id);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303656 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_INFO_HIGH,
Yun Parkb187d542016-11-14 18:10:04 -08003657 "w2i -- skb",
3658 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003659 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003660 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003661 return;
3662 }
3663
3664 iface_context = &hdd_ipa->iface_context[iface_id];
3665 adapter = iface_context->adapter;
3666
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303667 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003668 "w2i -- skb",
3669 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003670 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3671 hdd_ipa->stats.num_rx_excep++;
3672 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
3673 } else {
3674 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
3675 }
3676
3677 iface_context->stats.num_rx_ipa_excep++;
3678
3679 /* Disable to forward Intra-BSS Rx packets when
3680 * ap_isolate=1 in hostapd.conf
3681 */
Yun Park046101c2016-09-02 15:32:14 -07003682 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003683 /*
3684 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3685 * all Rx packets to IPA uC, which need to be forwarded
3686 * to other interface.
3687 * And, IPA driver will send back to WLAN host driver
3688 * through exception pipe with fw_desc field set by FW.
3689 * Here we are checking fw_desc field for FORWARD bit
3690 * set, and forward to Tx. Then copy to kernel stack
3691 * only when DISCARD bit is not set.
3692 */
3693 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003694 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3695 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3696 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003697 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003698 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303699 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003700 "Intra-BSS FWD is disabled-skip forward to Tx");
3701 }
3702
3703 hdd_ipa_send_skb_to_network(skb, adapter);
3704 break;
3705
3706 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303707 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708 "w2i cb wrong event: 0x%x", evt);
3709 return;
3710 }
3711}
3712
3713/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003714 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3715 * @priv: pointer to private data registered with IPA (we register a
3716 * pointer to the global IPA context)
3717 * @evt: the IPA event which triggered the callback
3718 * @data: data associated with the event
3719 *
3720 * Return: None
3721 */
3722static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3723 unsigned long data)
3724{
3725 cds_ssr_protect(__func__);
3726 __hdd_ipa_w2i_cb(priv, evt, data);
3727 cds_ssr_unprotect(__func__);
3728}
3729
3730/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731 * hdd_ipa_nbuf_cb() - IPA TX complete callback
3732 * @skb: packet buffer which was transmitted
3733 *
3734 * Return: None
3735 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303736void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003737{
3738 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3739
Govind Singhb6a89772016-08-12 11:23:35 +05303740 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05303741 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003742 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303743 ipa_free_skb((struct ipa_rx_data *)
3744 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003745
3746 hdd_ipa->stats.num_tx_comp_cnt++;
3747
3748 atomic_dec(&hdd_ipa->tx_ref_cnt);
3749
3750 hdd_ipa_rm_try_release(hdd_ipa);
3751}
3752
3753/**
3754 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
3755 * @iface_context: interface-specific IPA context
3756 * @ipa_tx_desc: packet data descriptor
3757 *
3758 * Return: None
3759 */
3760static void hdd_ipa_send_pkt_to_tl(
3761 struct hdd_ipa_iface_context *iface_context,
3762 struct ipa_rx_data *ipa_tx_desc)
3763{
3764 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003765 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303766 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003767
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303768 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003769 adapter = iface_context->adapter;
3770 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303771 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003772 ipa_free_skb(ipa_tx_desc);
3773 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303774 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003775 hdd_ipa_rm_try_release(hdd_ipa);
3776 return;
3777 }
3778
3779 /*
3780 * During CAC period, data packets shouldn't be sent over the air so
3781 * drop all the packets here
3782 */
3783 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
3784 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303785 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003786 iface_context->stats.num_tx_cac_drop++;
3787 hdd_ipa_rm_try_release(hdd_ipa);
3788 return;
3789 }
3790
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791 ++adapter->stats.tx_packets;
3792
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303793 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003794
3795 skb = ipa_tx_desc->skb;
3796
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303797 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303798 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003799 /* FIXME: This is broken. No such field in cb any more:
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08003800 * NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb;
3801 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003802 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05303803 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003804 ipa_tx_desc->dma_addr
3805 + HDD_IPA_WLAN_FRAG_HEADER
3806 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003807 ipa_tx_desc->skb->len -=
3808 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
3809 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05303810 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003811
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003812 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303813 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003814
3815 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
3816
Leo Changfdb45c32016-10-28 11:09:23 -07003817 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003818 (struct cdp_vdev *)iface_context->tl_context,
3819 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003820 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303821 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003822 ipa_free_skb(ipa_tx_desc);
3823 iface_context->stats.num_tx_err++;
3824 hdd_ipa_rm_try_release(hdd_ipa);
3825 return;
3826 }
3827
3828 atomic_inc(&hdd_ipa->tx_ref_cnt);
3829
3830 iface_context->stats.num_tx++;
3831
3832}
3833
3834/**
Leo Chang11545d62016-10-17 14:53:50 -07003835 * hdd_ipa_is_present() - get IPA hw status
3836 * @hdd_ctx: pointer to hdd context
3837 *
3838 * ipa_uc_reg_rdyCB is not directly designed to check
3839 * ipa hw status. This is an undocumented function which
3840 * has confirmed with IPA team.
3841 *
3842 * Return: true - ipa hw present
3843 * false - ipa hw not present
3844 */
3845bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
3846{
3847 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07003848 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07003849 return true;
3850 else
3851 return false;
3852}
3853
3854/**
Leo Chang69c39692016-10-12 20:11:12 -07003855 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003856 * @work: pointer to the scheduled work
3857 *
3858 * Called during PM resume to send packets to TL which were queued
3859 * while host was in the process of suspending.
3860 *
3861 * Return: None
3862 */
Leo Chang69c39692016-10-12 20:11:12 -07003863static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003864{
3865 struct hdd_ipa_priv *hdd_ipa = container_of(work,
3866 struct hdd_ipa_priv,
3867 pm_work);
3868 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303869 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003870 uint32_t dequeued = 0;
3871
Leo Chang69c39692016-10-12 20:11:12 -07003872 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
3873 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303874 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303875 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
3876 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303877 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003878
3879 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003880 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07003881 if (pm_tx_cb->exception) {
3882 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3883 "FLUSH EXCEPTION");
3884 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
3885 } else {
3886 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003887 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07003888 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303889 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003890 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303891 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07003892 qdf_wake_lock_release(&hdd_ipa->wake_lock,
3893 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003894
3895 hdd_ipa->stats.num_tx_dequeued += dequeued;
3896 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
3897 hdd_ipa->stats.num_max_pm_queue = dequeued;
3898}
3899
3900/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003901 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003902 * @priv: pointer to private data registered with IPA (we register a
3903 * pointer to the interface-specific IPA context)
3904 * @evt: the IPA event which triggered the callback
3905 * @data: data associated with the event
3906 *
3907 * Return: None
3908 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003909static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003910 unsigned long data)
3911{
3912 struct hdd_ipa_priv *hdd_ipa = NULL;
3913 struct ipa_rx_data *ipa_tx_desc;
3914 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303915 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003916 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303917 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918
Mukul Sharma81661ae2015-10-30 20:26:02 +05303919 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003920 ipa_tx_desc = (struct ipa_rx_data *)data;
3921 hdd_ipa = iface_context->hdd_ipa;
3922
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003924 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
3925 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003926 iface_context->stats.num_tx_drop++;
3927 return;
3928 }
3929
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003930 /*
3931 * When SSR is going on or driver is unloading, just drop the packets.
3932 * During SSR, there is no use in queueing the packets as STA has to
3933 * connect back any way
3934 */
3935 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303936 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003937 ipa_free_skb(ipa_tx_desc);
3938 iface_context->stats.num_tx_drop++;
3939 return;
3940 }
3941
3942 skb = ipa_tx_desc->skb;
3943
Yun Parkb187d542016-11-14 18:10:04 -08003944 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
3945 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003946
3947 /*
3948 * If PROD resource is not requested here then there may be cases where
3949 * IPA hardware may be clocked down because of not having proper
3950 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
3951 * workaround to request PROD resource while data is going over CONS
3952 * pipe to prevent the IPA hardware clockdown.
3953 */
3954 hdd_ipa_rm_request(hdd_ipa);
3955
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303956 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003957 /*
3958 * If host is still suspended then queue the packets and these will be
3959 * drained later when resume completes. When packet is arrived here and
3960 * host is suspended, this means that there is already resume is in
3961 * progress.
3962 */
3963 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303964 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003965 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
3966 pm_tx_cb->iface_context = iface_context;
3967 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303968 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003969 hdd_ipa->stats.num_tx_queued++;
3970
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303971 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003972 return;
3973 }
3974
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303975 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003976
3977 /*
3978 * If we are here means, host is not suspended, wait for the work queue
3979 * to finish.
3980 */
3981#ifdef WLAN_OPEN_SOURCE
3982 flush_work(&hdd_ipa->pm_work);
3983#endif
3984
3985 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
3986}
3987
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003988/*
3989 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
3990 * @priv: pointer to private data registered with IPA (we register a
3991 * pointer to the interface-specific IPA context)
3992 * @evt: the IPA event which triggered the callback
3993 * @data: data associated with the event
3994 *
3995 * Return: None
3996 */
3997static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
3998 unsigned long data)
3999{
4000 cds_ssr_protect(__func__);
4001 __hdd_ipa_i2w_cb(priv, evt, data);
4002 cds_ssr_unprotect(__func__);
4003}
4004
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004005/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004006 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004007 * @hdd_ctx: Global HDD context
4008 *
4009 * Return: 0 on success, negativer errno on error
4010 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004011static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004013 struct hdd_ipa_priv *hdd_ipa;
4014
4015 if (wlan_hdd_validate_context(hdd_ctx))
4016 return 0;
4017
4018 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004019
4020 if (!hdd_ipa_is_enabled(hdd_ctx))
4021 return 0;
4022
4023 /*
4024 * Check if IPA is ready for suspend, If we are here means, there is
4025 * high chance that suspend would go through but just to avoid any race
4026 * condition after suspend started, these checks are conducted before
4027 * allowing to suspend.
4028 */
4029 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4030 return -EAGAIN;
4031
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304032 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004033
4034 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304035 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004036 return -EAGAIN;
4037 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304038 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004039
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304040 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004041 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304042 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004043
4044 return 0;
4045}
4046
4047/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004048 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4049 * @hdd_ctx: Global HDD context
4050 *
4051 * Return: 0 on success, negativer errno on error
4052 */
4053int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4054{
4055 int ret;
4056
4057 cds_ssr_protect(__func__);
4058 ret = __hdd_ipa_suspend(hdd_ctx);
4059 cds_ssr_unprotect(__func__);
4060
4061 return ret;
4062}
4063
4064/**
4065 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004066 * hdd_ctx: Global HDD context
4067 *
4068 * Return: 0 on success, negative errno on error
4069 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004070static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004072 struct hdd_ipa_priv *hdd_ipa;
4073
4074 if (wlan_hdd_validate_context(hdd_ctx))
4075 return 0;
4076
4077 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004078
4079 if (!hdd_ipa_is_enabled(hdd_ctx))
4080 return 0;
4081
4082 schedule_work(&hdd_ipa->pm_work);
4083
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304084 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004085 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304086 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004087
4088 return 0;
4089}
4090
4091/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004092 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4093 * hdd_ctx: Global HDD context
4094 *
4095 * Return: 0 on success, negative errno on error
4096 */
4097int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4098{
4099 int ret;
4100
4101 cds_ssr_protect(__func__);
4102 ret = __hdd_ipa_resume(hdd_ctx);
4103 cds_ssr_unprotect(__func__);
4104
4105 return ret;
4106}
4107
4108/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004109 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4110 * @hdd_ipa: Global HDD IPA context
4111 *
4112 * Return: 0 on success, negative errno on error
4113 */
4114static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4115{
4116 int i, ret = 0;
4117 struct ipa_sys_connect_params *ipa;
4118 uint32_t desc_fifo_sz;
4119
4120 /* The maximum number of descriptors that can be provided to a BAM at
4121 * once is one less than the total number of descriptors that the buffer
4122 * can contain.
4123 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4124 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4125 * be provided at once.
4126 * Because of above requirement, one extra descriptor will be added to
4127 * make sure hardware always has one descriptor.
4128 */
4129 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4130 + sizeof(struct sps_iovec);
4131
4132 /*setup TX pipes */
4133 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4134 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4135
4136 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4137 ipa->desc_fifo_sz = desc_fifo_sz;
4138 ipa->priv = &hdd_ipa->iface_context[i];
4139 ipa->notify = hdd_ipa_i2w_cb;
4140
4141 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4142 ipa->ipa_ep_cfg.hdr.hdr_len =
4143 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4144 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4145 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4146 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4147 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4148 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4149 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4150 } else {
4151 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4152 }
4153 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4154
4155 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4156 ipa->keep_ipa_awake = 1;
4157
4158 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4159 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304160 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004161 " ret: %d", i, ret);
4162 goto setup_sys_pipe_fail;
4163 }
4164 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4165 }
4166
4167 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4168 /*
4169 * Hard code it here, this can be extended if in case
4170 * PROD pipe is also per interface.
4171 * Right now there is no advantage of doing this.
4172 */
4173 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4174
4175 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4176
4177 ipa->client = hdd_ipa->prod_client;
4178
4179 ipa->desc_fifo_sz = desc_fifo_sz;
4180 ipa->priv = hdd_ipa;
4181 ipa->notify = hdd_ipa_w2i_cb;
4182
4183 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4184 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4185 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4186 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4187
4188 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4189 ipa->keep_ipa_awake = 1;
4190
4191 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4192 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304193 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004194 "Failed for RX pipe: %d", ret);
4195 goto setup_sys_pipe_fail;
4196 }
4197 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4198 }
4199
4200 return ret;
4201
4202setup_sys_pipe_fail:
4203
4204 while (--i >= 0) {
4205 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304206 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004207 sizeof(struct hdd_ipa_sys_pipe));
4208 }
4209
4210 return ret;
4211}
4212
4213/**
4214 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4215 * @hdd_ipa: Global HDD IPA context
4216 *
4217 * Return: None
4218 */
4219static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4220{
4221 int ret = 0, i;
4222 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4223 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4224 ret =
4225 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4226 conn_hdl);
4227 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304228 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004229 ret);
4230
4231 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4232 }
4233 }
4234}
4235
4236/**
4237 * hdd_ipa_register_interface() - register IPA interface
4238 * @hdd_ipa: Global IPA context
4239 * @iface_context: Per-interface IPA context
4240 *
4241 * Return: 0 on success, negative errno on error
4242 */
4243static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
4244 struct hdd_ipa_iface_context
4245 *iface_context)
4246{
4247 struct ipa_tx_intf tx_intf;
4248 struct ipa_rx_intf rx_intf;
4249 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
4250 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
4251 char *ifname = iface_context->adapter->dev->name;
4252
4253 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
4254 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
4255
4256 int num_prop = 1;
4257 int ret = 0;
4258
4259 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
4260 num_prop++;
4261
4262 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
4263 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304264 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004265 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304266 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004267 goto register_interface_fail;
4268 }
4269
4270 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
4271 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304272 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004273 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304274 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004275 goto register_interface_fail;
4276 }
4277
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304278 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
4279 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280
4281 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4282 ifname, HDD_IPA_IPV4_NAME_EXT);
4283 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4284 ifname, HDD_IPA_IPV6_NAME_EXT);
4285
4286 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4287 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
4288 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4289 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4290
4291 /*
4292 * Interface ID is 3rd byte in the CLD header. Add the meta data and
4293 * mask to identify the interface in IPA hardware
4294 */
4295 rx_prop[IPA_IP_v4].attrib.meta_data =
4296 htonl(iface_context->adapter->sessionId << 16);
4297 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4298
4299 rx_intf.num_props++;
4300 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4301 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4302 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
4303 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4304 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4305 rx_prop[IPA_IP_v4].attrib.meta_data =
4306 htonl(iface_context->adapter->sessionId << 16);
4307 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4308
4309 rx_intf.num_props++;
4310 }
4311
4312 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4313 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4314 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4315 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
4316 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
4317 IPA_RESOURCE_NAME_MAX);
4318 tx_intf.num_props++;
4319
4320 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4321 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4322 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4323 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4324 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
4325 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
4326 IPA_RESOURCE_NAME_MAX);
4327 tx_intf.num_props++;
4328 }
4329
4330 tx_intf.prop = tx_prop;
4331 rx_intf.prop = rx_prop;
4332
4333 /* Call the ipa api to register interface */
4334 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
4335
4336register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304337 qdf_mem_free(tx_prop);
4338 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004339 return ret;
4340}
4341
4342/**
4343 * hdd_remove_ipa_header() - Remove a specific header from IPA
4344 * @name: Name of the header to be removed
4345 *
4346 * Return: None
4347 */
4348static void hdd_ipa_remove_header(char *name)
4349{
4350 struct ipa_ioc_get_hdr hdrlookup;
4351 int ret = 0, len;
4352 struct ipa_ioc_del_hdr *ipa_hdr;
4353
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304354 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
4356 ret = ipa_get_hdr(&hdrlookup);
4357 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304358 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004359 name, ret);
4360 return;
4361 }
4362
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304363 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004364 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304365 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004366 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304367 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004368 return;
4369 }
4370 ipa_hdr->num_hdls = 1;
4371 ipa_hdr->commit = 0;
4372 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
4373 ipa_hdr->hdl[0].status = -1;
4374 ret = ipa_del_hdr(ipa_hdr);
4375 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304376 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004377 ret);
4378
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304379 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004380}
4381
4382/**
Yun Parkb187d542016-11-14 18:10:04 -08004383 * wlan_ipa_add_hdr() - Add IPA Tx header
4384 * @ipa_hdr: pointer to IPA header addition parameters
4385 *
4386 * Call IPA API to add IPA Tx header descriptor
4387 * and dump Tx header struct
4388 *
4389 * Return: 0 for success, non-zero for failure
4390 */
4391static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
4392{
4393 int ret;
4394
4395 hdd_info("==== IPA Tx Header ====\n"
4396 "name: %s\n"
4397 "hdr_len: %d\n"
4398 "type: %d\n"
4399 "is_partial: %d\n"
4400 "hdr_hdl: 0x%x\n"
4401 "status: %d\n"
4402 "is_eth2_ofst_valid: %d\n"
4403 "eth2_ofst: %d\n",
4404 ipa_hdr->hdr[0].name,
4405 ipa_hdr->hdr[0].hdr_len,
4406 ipa_hdr->hdr[0].type,
4407 ipa_hdr->hdr[0].is_partial,
4408 ipa_hdr->hdr[0].hdr_hdl,
4409 ipa_hdr->hdr[0].status,
4410 ipa_hdr->hdr[0].is_eth2_ofst_valid,
4411 ipa_hdr->hdr[0].eth2_ofst);
4412
4413 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:",
4414 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4415
4416 ret = ipa_add_hdr(ipa_hdr);
4417 return ret;
4418}
4419
4420/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004421 * hdd_ipa_add_header_info() - Add IPA header for a given interface
4422 * @hdd_ipa: Global HDD IPA context
4423 * @iface_context: Interface-specific HDD IPA context
4424 * @mac_addr: Interface MAC address
4425 *
4426 * Return: 0 on success, negativer errno value on error
4427 */
4428static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
4429 struct hdd_ipa_iface_context *iface_context,
4430 uint8_t *mac_addr)
4431{
4432 hdd_adapter_t *adapter = iface_context->adapter;
4433 char *ifname;
4434 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
4435 int ret = -EINVAL;
4436 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
4437 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
4438
4439 ifname = adapter->dev->name;
4440
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304441 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004442 ifname, mac_addr);
4443
4444 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304445 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004446 + sizeof(struct ipa_hdr_add));
4447 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304448 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004449 "%s: ipa_hdr allocation failed", ifname);
4450 ret = -ENOMEM;
4451 goto end;
4452 }
4453
4454 ipa_hdr->commit = 0;
4455 ipa_hdr->num_hdrs = 1;
4456
4457 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4458 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4459 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4460 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4461 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304462 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004463 "ifname=%s, vdev_id=%d",
4464 ifname, uc_tx_hdr->ipa_hd.vdev_id);
4465 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4466 ifname, HDD_IPA_IPV4_NAME_EXT);
4467 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
4468 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
4469 ipa_hdr->hdr[0].is_partial = 1;
4470 ipa_hdr->hdr[0].hdr_hdl = 0;
4471 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4472 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4473
Yun Parkb187d542016-11-14 18:10:04 -08004474 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004475 } else {
4476 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4477
4478 /* Set the Source MAC */
4479 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
4480 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4481
4482 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4483 ifname, HDD_IPA_IPV4_NAME_EXT);
4484 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4485 ipa_hdr->hdr[0].is_partial = 1;
4486 ipa_hdr->hdr[0].hdr_hdl = 0;
4487 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4488 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4489
4490 /* Set the type to IPV4 in the header */
4491 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
4492
4493 ret = ipa_add_hdr(ipa_hdr);
4494 }
4495 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304496 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004497 ifname, ret);
4498 goto end;
4499 }
4500
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304501 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4503
4504 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4505 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4506 ifname, HDD_IPA_IPV6_NAME_EXT);
4507
4508 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4509 uc_tx_hdr =
4510 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4511 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004512 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004513 } else {
4514 /* Set the type to IPV6 in the header */
4515 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4516 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004517 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004518 }
4519
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004520 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304521 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004522 "%s: IPv6 add hdr failed: %d", ifname, ret);
4523 goto clean_ipv4_hdr;
4524 }
4525
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304526 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004527 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4528 }
4529
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304530 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004531
4532 return ret;
4533
4534clean_ipv4_hdr:
4535 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4536 ifname, HDD_IPA_IPV4_NAME_EXT);
4537 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
4538end:
4539 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304540 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004541
4542 return ret;
4543}
4544
4545/**
4546 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
4547 * @adapter: Adapter upon which IPA was previously configured
4548 *
4549 * Return: None
4550 */
4551static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
4552{
4553 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4554 int ret;
4555 char name_ipa[IPA_RESOURCE_NAME_MAX];
4556
4557 /* Remove the headers */
4558 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4559 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
4560 hdd_ipa_remove_header(name_ipa);
4561
4562 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4563 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4564 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
4565 hdd_ipa_remove_header(name_ipa);
4566 }
4567 /* unregister the interface with IPA */
4568 ret = ipa_deregister_intf(adapter->dev->name);
4569 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304570 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004571 "%s: ipa_deregister_intf fail: %d",
4572 adapter->dev->name, ret);
4573}
4574
4575/**
4576 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4577 * @iface_context: interface-specific IPA context
4578 *
4579 * Return: None
4580 */
4581static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4582{
4583 if (iface_context == NULL)
4584 return;
4585
4586 hdd_ipa_clean_hdr(iface_context->adapter);
4587
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304588 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004589 iface_context->adapter->ipa_context = NULL;
4590 iface_context->adapter = NULL;
4591 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304592 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004593 iface_context->ifa_address = 0;
4594 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304595 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004596 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304597 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004598 }
4599 iface_context->hdd_ipa->num_iface--;
4600}
4601
4602/**
4603 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4604 * @hdd_ipa: HDD IPA global context
4605 * @adapter: Interface upon which IPA is being setup
4606 * @sta_id: Station ID of the API instance
4607 *
4608 * Return: 0 on success, negative errno value on error
4609 */
4610static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
4611 hdd_adapter_t *adapter, uint8_t sta_id)
4612{
4613 struct hdd_ipa_iface_context *iface_context = NULL;
4614 void *tl_context = NULL;
4615 int i, ret = 0;
4616
4617 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4618 * channel change indication. Since these indications are sent by lower
4619 * layer as SAP updates and IPA doesn't have to do anything for these
4620 * updates so ignoring!
4621 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004622 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623 return 0;
4624
4625 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4626 if (hdd_ipa->iface_context[i].adapter == NULL) {
4627 iface_context = &(hdd_ipa->iface_context[i]);
4628 break;
4629 }
4630 }
4631
4632 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304633 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 "All the IPA interfaces are in use");
4635 ret = -ENOMEM;
4636 goto end;
4637 }
4638
4639 adapter->ipa_context = iface_context;
4640 iface_context->adapter = adapter;
4641 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004642 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07004643 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304645 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004646 "Not able to get TL context sta_id: %d", sta_id);
4647 ret = -EINVAL;
4648 goto end;
4649 }
4650
4651 iface_context->tl_context = tl_context;
4652
4653 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
4654 adapter->dev->dev_addr);
4655
4656 if (ret)
4657 goto end;
4658
4659 /* Configure the TX and RX pipes filter rules */
4660 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
4661 if (ret)
4662 goto cleanup_header;
4663
4664 hdd_ipa->num_iface++;
4665 return ret;
4666
4667cleanup_header:
4668
4669 hdd_ipa_clean_hdr(adapter);
4670end:
4671 if (iface_context)
4672 hdd_ipa_cleanup_iface(iface_context);
4673 return ret;
4674}
4675
Yun Parka27049a2016-10-11 12:30:49 -07004676#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004677/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004678 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004679 * @mcc_mode: 0=MCC/1=SCC
4680 *
4681 * Return: 0 on success, negative errno value on error
4682 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004683static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004684{
4685 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304686 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004687 hdd_adapter_t *pAdapter;
4688 struct ipa_msg_meta meta;
4689 struct ipa_wlan_msg *msg;
4690 int ret;
4691
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004692 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004693 return -EINVAL;
4694
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004695 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4696 return -EINVAL;
4697
4698 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004699 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004700 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304701 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004702 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08004703 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004704 pAdapter->device_mode == QDF_SAP_MODE) {
4705 hdd_info("MCC->SCC: Flush TxRx queue(d_mode=%d)",
4706 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707 hdd_deinit_tx_rx(pAdapter);
4708 }
4709 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004710 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004711 adapter_node = next;
4712 }
4713 }
4714
4715 /* Send SCC/MCC Switching event to IPA */
4716 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304717 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004718 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004719 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004720 return -ENOMEM;
4721 }
4722
4723 meta.msg_type = mcc_mode ?
4724 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004725 hdd_info("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004726
4727 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4728
4729 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004730 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004731 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304732 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004733 }
4734
4735 return ret;
4736}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004737
4738/**
4739 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4740 * @mcc_mode: 0=MCC/1=SCC
4741 *
4742 * Return: 0 on success, negative errno value on error
4743 */
4744int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
4745{
4746 int ret;
4747
4748 cds_ssr_protect(__func__);
4749 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4750 cds_ssr_unprotect(__func__);
4751
4752 return ret;
4753}
Yun Parka27049a2016-10-11 12:30:49 -07004754#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004755
4756/**
4757 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4758 * @event: IPA WLAN event to be converted to a string
4759 *
4760 * Return: ASCII string representing the IPA WLAN event
4761 */
4762static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4763{
4764 switch (event) {
4765 case WLAN_CLIENT_CONNECT:
4766 return "WLAN_CLIENT_CONNECT";
4767 case WLAN_CLIENT_DISCONNECT:
4768 return "WLAN_CLIENT_DISCONNECT";
4769 case WLAN_CLIENT_POWER_SAVE_MODE:
4770 return "WLAN_CLIENT_POWER_SAVE_MODE";
4771 case WLAN_CLIENT_NORMAL_MODE:
4772 return "WLAN_CLIENT_NORMAL_MODE";
4773 case SW_ROUTING_ENABLE:
4774 return "SW_ROUTING_ENABLE";
4775 case SW_ROUTING_DISABLE:
4776 return "SW_ROUTING_DISABLE";
4777 case WLAN_AP_CONNECT:
4778 return "WLAN_AP_CONNECT";
4779 case WLAN_AP_DISCONNECT:
4780 return "WLAN_AP_DISCONNECT";
4781 case WLAN_STA_CONNECT:
4782 return "WLAN_STA_CONNECT";
4783 case WLAN_STA_DISCONNECT:
4784 return "WLAN_STA_DISCONNECT";
4785 case WLAN_CLIENT_CONNECT_EX:
4786 return "WLAN_CLIENT_CONNECT_EX";
4787
4788 case IPA_WLAN_EVENT_MAX:
4789 default:
4790 return "UNKNOWN";
4791 }
4792}
4793
4794/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004795 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4796 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4797 *
4798 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4799 */
4800static enum ipa_wlan_event
4801hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4802{
4803 enum ipa_wlan_event ipa_event;
4804
4805 switch (hdd_ipa_event_type) {
4806 case HDD_IPA_CLIENT_CONNECT:
4807 ipa_event = WLAN_CLIENT_CONNECT;
4808 break;
4809 case HDD_IPA_CLIENT_DISCONNECT:
4810 ipa_event = WLAN_CLIENT_DISCONNECT;
4811 break;
4812 case HDD_IPA_AP_CONNECT:
4813 ipa_event = WLAN_AP_CONNECT;
4814 break;
4815 case HDD_IPA_AP_DISCONNECT:
4816 ipa_event = WLAN_AP_DISCONNECT;
4817 break;
4818 case HDD_IPA_STA_CONNECT:
4819 ipa_event = WLAN_STA_CONNECT;
4820 break;
4821 case HDD_IPA_STA_DISCONNECT:
4822 ipa_event = WLAN_STA_DISCONNECT;
4823 break;
4824 case HDD_IPA_CLIENT_CONNECT_EX:
4825 ipa_event = WLAN_CLIENT_CONNECT_EX;
4826 break;
4827 case HDD_IPA_WLAN_EVENT_MAX:
4828 default:
4829 ipa_event = IPA_WLAN_EVENT_MAX;
4830 break;
4831 }
4832 return ipa_event;
4833
4834}
4835
4836/**
4837 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004838 * @adapter: adapter upon which the event was received
4839 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004840 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004841 * @mac_address: MAC address associated with the event
4842 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004843 * This function is meant to be called from within wlan_hdd_ipa.c
4844 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004845 * Return: 0 on success, negative errno value on error
4846 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07004847static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004848 enum ipa_wlan_event type, uint8_t *mac_addr)
4849{
4850 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4851 struct ipa_msg_meta meta;
4852 struct ipa_wlan_msg *msg;
4853 struct ipa_wlan_msg_ex *msg_ex = NULL;
4854 int ret;
4855
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304856 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004857 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
4858 mac_addr, sta_id);
4859
4860 if (type >= IPA_WLAN_EVENT_MAX)
4861 return -EINVAL;
4862
4863 if (WARN_ON(is_zero_ether_addr(mac_addr)))
4864 return -EINVAL;
4865
4866 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304867 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004868 return -EINVAL;
4869 }
4870
4871 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
4872 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08004873 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004874 return 0;
4875 }
4876
4877 /*
4878 * During IPA UC resource loading/unloading new events can be issued.
4879 * Store the events separately and handle them later.
4880 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004881 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4882 if (hdd_ipa->resource_loading) {
4883 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004884 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08004885
Yun Park7c4f31b2016-11-30 10:09:21 -08004886 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA resource %s inprogress",
4887 hdd_ipa->resource_loading ? "load":"unload");
4888
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004889 hdd_err("IPA resource %s inprogress",
4890 hdd_ipa->resource_loading ? "load":"unload");
Yun Parkf19e07d2015-11-20 11:34:27 -08004891
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004892 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004893
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004894 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4895 if (pending_event_count >= HDD_IPA_MAX_PENDING_EVENT_COUNT) {
4896 hdd_notice("Reached max pending event count");
4897 qdf_list_remove_front(&hdd_ipa->pending_event,
4898 (qdf_list_node_t **)&pending_event);
4899 } else {
4900 pending_event =
4901 (struct ipa_uc_pending_event *)qdf_mem_malloc(
4902 sizeof(struct ipa_uc_pending_event));
4903 }
4904
4905 if (!pending_event) {
Yun Park7c4f31b2016-11-30 10:09:21 -08004906 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4907 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004908 qdf_mutex_release(&hdd_ipa->event_lock);
4909 return -ENOMEM;
4910 }
4911
4912 pending_event->adapter = adapter;
4913 pending_event->sta_id = sta_id;
4914 pending_event->type = type;
4915 qdf_mem_copy(pending_event->mac_addr,
4916 mac_addr,
4917 QDF_MAC_ADDR_SIZE);
4918 qdf_list_insert_back(&hdd_ipa->pending_event,
4919 &pending_event->node);
4920
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304921 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004922 return 0;
4923 } else if (hdd_ipa->resource_unloading) {
4924 hdd_err("%s: IPA resource unload inprogress", __func__);
4925 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004926 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004927 }
4928
4929 hdd_ipa->stats.event[type]++;
4930
Leo Chang3bc8fed2015-11-13 10:59:47 -08004931 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004932 switch (type) {
4933 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004934 qdf_mutex_acquire(&hdd_ipa->event_lock);
4935
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004936 /* STA already connected and without disconnect, connect again
4937 * This is Roaming scenario
4938 */
4939 if (hdd_ipa->sta_connected)
4940 hdd_ipa_cleanup_iface(adapter->ipa_context);
4941
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004942 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4943 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304944 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004945 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004946 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004947
Yun Park8f289c82016-10-18 16:38:21 -07004948 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4949 (hdd_ipa->sap_num_connected_sta > 0) &&
4950 !hdd_ipa->sta_connected) {
4951 qdf_mutex_release(&hdd_ipa->event_lock);
4952 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004953 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004954 qdf_mutex_acquire(&hdd_ipa->event_lock);
4955 }
4956
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004957 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004958 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004959 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004960
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004961 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07004962
4963 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004964 break;
4965
4966 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004967 qdf_mutex_acquire(&hdd_ipa->event_lock);
4968
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004969 /* For DFS channel we get two start_bss event (before and after
4970 * CAC). Also when ACS range includes both DFS and non DFS
4971 * channels, we could possibly change channel many times due to
4972 * RADAR detection and chosen channel may not be a DFS channels.
4973 * So dont return error here. Just discard the event.
4974 */
Yun Park8f289c82016-10-18 16:38:21 -07004975 if (adapter->ipa_context) {
4976 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004977 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07004978 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004979
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004980 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4981 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004982 hdd_err("%s: Evt: %d, Interface setup failed",
4983 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304984 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004985 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004986 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004987
Yun Park8f289c82016-10-18 16:38:21 -07004988 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4989 qdf_mutex_release(&hdd_ipa->event_lock);
4990 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004991 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004992 qdf_mutex_acquire(&hdd_ipa->event_lock);
4993 }
4994
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004995 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004996 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004997 (adapter->ipa_context))->iface_id;
4998
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304999 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005000 break;
5001
5002 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305003 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005004
5005 if (!hdd_ipa->sta_connected) {
Yun Parkb187d542016-11-14 18:10:04 -08005006 hdd_err("%s: Evt: %d, STA already disconnected",
5007 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305008 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005009 return -EINVAL;
5010 }
Yun Parka37592b2016-06-11 17:10:28 -07005011
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005012 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005013
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005014 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08005015 hdd_notice("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005016 msg_ex->name);
5017 } else {
5018 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005019 if (!hdd_ipa->num_iface &&
5020 (HDD_IPA_UC_NUM_WDI_PIPE ==
5021 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005022 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005023 }
5024
Yun Park74127cf2016-09-18 11:22:41 -07005025 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5026 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005027 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005028 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005029 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005030 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005031 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5032 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005033 }
5034
Yun Park8f289c82016-10-18 16:38:21 -07005035 hdd_ipa_cleanup_iface(adapter->ipa_context);
5036
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305037 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005038 break;
5039
5040 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005041 qdf_mutex_acquire(&hdd_ipa->event_lock);
5042
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005043 if (!adapter->ipa_context) {
Yun Parkb187d542016-11-14 18:10:04 -08005044 hdd_err("%s: Evt: %d, SAP already disconnected",
5045 msg_ex->name, meta.msg_type);
Yun Park8f289c82016-10-18 16:38:21 -07005046 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005047 return -EINVAL;
5048 }
5049
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005050 if ((!hdd_ipa->num_iface) &&
5051 (HDD_IPA_UC_NUM_WDI_PIPE ==
5052 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005053 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005054 /*
5055 * We disable WDI pipes directly here since
5056 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5057 * processed when unloading WLAN driver is in
5058 * progress
5059 */
5060 hdd_ipa_uc_disable_pipes(hdd_ipa);
5061 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305062 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005063 "NO INTF left but still pipe clean up");
5064 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5065 }
5066 }
5067
5068 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005069 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005070 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005071 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005072 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005073 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5074 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005075 }
Yun Parka37592b2016-06-11 17:10:28 -07005076
Yun Park8f289c82016-10-18 16:38:21 -07005077 hdd_ipa_cleanup_iface(adapter->ipa_context);
5078
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305079 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005080 break;
5081
5082 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005083 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305084 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005085 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305086 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005087 return 0;
5088 }
5089
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305090 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005091 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5092 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005093 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305094 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005095 "%s: STA ID %d found, not valid",
5096 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005097 return 0;
5098 }
Yun Park312f71a2015-12-08 10:22:42 -08005099
5100 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005101 if (hdd_ipa->sap_num_connected_sta == 0 &&
5102 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005103 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005104 hdd_ipa->sta_connected) {
5105 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005106 hdd_ipa_uc_offload_enable_disable(
5107 hdd_get_adapter(hdd_ipa->hdd_ctx,
5108 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005109 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005110 qdf_mutex_acquire(&hdd_ipa->event_lock);
5111 }
Yun Parka37592b2016-06-11 17:10:28 -07005112
Yun Park312f71a2015-12-08 10:22:42 -08005113 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5114 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305115 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005116 "%s: handle 1st con ret %d",
5117 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005118
5119 if (hdd_ipa_uc_sta_is_enabled(
5120 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005121 hdd_ipa->sta_connected) {
5122 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005123 hdd_ipa_uc_offload_enable_disable(
5124 hdd_get_adapter(
5125 hdd_ipa->hdd_ctx,
5126 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005127 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005128 } else {
5129 qdf_mutex_release(&hdd_ipa->event_lock);
5130 }
Yun Parka37592b2016-06-11 17:10:28 -07005131
Yun Park312f71a2015-12-08 10:22:42 -08005132 return ret;
5133 }
5134 }
5135
5136 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005137
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305138 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005139
5140 meta.msg_type = type;
5141 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5142 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305143 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005144
5145 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305146 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005147 "msg_ex allocation failed");
5148 return -ENOMEM;
5149 }
5150 strlcpy(msg_ex->name, adapter->dev->name,
5151 IPA_RESOURCE_NAME_MAX);
5152 msg_ex->num_of_attribs = 1;
5153 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5154 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5155 msg_ex->attribs[0].offset =
5156 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5157 } else {
5158 msg_ex->attribs[0].offset =
5159 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5160 }
5161 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5162 IPA_MAC_ADDR_SIZE);
5163
5164 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5165
5166 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305167 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305168 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305169 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005170 return ret;
5171 }
5172 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005173 return ret;
5174
5175 case WLAN_CLIENT_DISCONNECT:
5176 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305177 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005178 "%s: IPA UC OFFLOAD NOT ENABLED",
5179 msg_ex->name);
5180 return 0;
5181 }
5182
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305183 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005184 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305185 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005186 "%s: STA ID %d NOT found, not valid",
5187 msg_ex->name, sta_id);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305188 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005189 return 0;
5190 }
5191 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005192
Yun Park9b5030f2016-11-08 12:02:37 -08005193 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005194 if (!hdd_ipa->sap_num_connected_sta &&
5195 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005196 if ((false == hdd_ipa->resource_unloading)
5197 && (HDD_IPA_UC_NUM_WDI_PIPE ==
5198 hdd_ipa->activated_fw_pipe)) {
5199 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5200 }
5201
Yun Park8f289c82016-10-18 16:38:21 -07005202 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005203
5204 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5205 hdd_ipa->sta_connected)
5206 hdd_ipa_uc_offload_enable_disable(
5207 hdd_get_adapter(hdd_ipa->hdd_ctx,
5208 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005209 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005210 } else {
5211 qdf_mutex_release(&hdd_ipa->event_lock);
5212 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005213 break;
5214
5215 default:
5216 return 0;
5217 }
5218
5219 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305220 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005221 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305222 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005223 return -ENOMEM;
5224 }
5225
5226 meta.msg_type = type;
5227 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5228 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5229
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305230 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005231 msg->name, meta.msg_type);
5232
5233 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5234
5235 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005236 hdd_err("%s: Evt: %d fail:%d",
5237 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305238 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005239 return ret;
5240 }
5241
5242 hdd_ipa->stats.num_send_msg++;
5243
5244end:
5245 return ret;
5246}
5247
5248/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005249 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005250 * @adapter: adapter upon which the event was received
5251 * @sta_id: station id for the event
5252 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5253 * @mac_address: MAC address associated with the event
5254 *
5255 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5256 *
5257 * Return: 0 on success, negative errno value on error
5258 */
5259int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
5260 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5261{
5262 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005263 int ret = 0;
5264
5265 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005266
Leo Changa202b522016-10-14 16:13:50 -07005267 /* Data path offload only support for STA and SAP mode */
5268 if ((QDF_STA_MODE == adapter->device_mode) ||
5269 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005270 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005271
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005272 cds_ssr_unprotect(__func__);
5273
5274 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005275}
5276
5277/**
5278 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5279 * @hdd_ipa: Global HDD IPA context
5280 *
5281 * Return: None
5282 */
5283static void
5284hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5285{
5286 unsigned int pending_event_count;
5287 struct ipa_uc_pending_event *pending_event = NULL;
5288
5289 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
5290 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
5291 "%s, Pending Event Count %d", __func__, pending_event_count);
5292 if (!pending_event_count) {
5293 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
5294 "%s, No Pending Event", __func__);
5295 return;
5296 }
5297
5298 qdf_list_remove_front(&hdd_ipa->pending_event,
5299 (qdf_list_node_t **)&pending_event);
5300 while (pending_event != NULL) {
5301 __hdd_ipa_wlan_evt(pending_event->adapter,
5302 pending_event->type,
5303 pending_event->sta_id,
5304 pending_event->mac_addr);
5305 qdf_mem_free(pending_event);
5306 pending_event = NULL;
5307 qdf_list_remove_front(&hdd_ipa->pending_event,
5308 (qdf_list_node_t **)&pending_event);
5309 }
5310}
5311
5312/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005313 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5314 * @state: IPA RM state value
5315 *
5316 * Return: ASCII string representing the IPA RM state
5317 */
5318static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5319{
5320 switch (state) {
5321 case HDD_IPA_RM_RELEASED:
5322 return "RELEASED";
5323 case HDD_IPA_RM_GRANT_PENDING:
5324 return "GRANT_PENDING";
5325 case HDD_IPA_RM_GRANTED:
5326 return "GRANTED";
5327 }
5328
5329 return "UNKNOWN";
5330}
5331
5332/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005333 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005334 * @hdd_ctx: HDD global context
5335 *
5336 * Allocate hdd_ipa resources, ipa pipe resource and register
5337 * wlan interface with IPA module.
5338 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305339 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005340 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005341static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005342{
5343 struct hdd_ipa_priv *hdd_ipa = NULL;
5344 int ret, i;
5345 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005346 struct ol_txrx_pdev_t *pdev = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005347
5348 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305349 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005350
Yun Parkbaa62862017-01-18 13:43:34 -08005351 ENTER();
5352
5353 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005354 if (!pdev) {
5355 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5356 goto fail_return;
5357 }
5358
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305359 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005360 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305361 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005362 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005363 }
5364
5365 hdd_ctx->hdd_ipa = hdd_ipa;
5366 ghdd_ipa = hdd_ipa;
5367 hdd_ipa->hdd_ctx = hdd_ctx;
5368 hdd_ipa->num_iface = 0;
5369
5370 /* Create the interface context */
5371 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5372 iface_context = &hdd_ipa->iface_context[i];
5373 iface_context->hdd_ipa = hdd_ipa;
5374 iface_context->cons_client =
5375 hdd_ipa_adapter_2_client[i].cons_client;
5376 iface_context->prod_client =
5377 hdd_ipa_adapter_2_client[i].prod_client;
5378 iface_context->iface_id = i;
5379 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305380 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005381 }
5382 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005383 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5384 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005385 }
5386
Leo Chang69c39692016-10-12 20:11:12 -07005387 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305388 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305389 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005390
5391 ret = hdd_ipa_setup_rm(hdd_ipa);
5392 if (ret)
5393 goto fail_setup_rm;
5394
5395 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5396 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305397 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005398 hdd_ipa->sap_num_connected_sta = 0;
5399 hdd_ipa->ipa_tx_packets_diff = 0;
5400 hdd_ipa->ipa_rx_packets_diff = 0;
5401 hdd_ipa->ipa_p_tx_packets = 0;
5402 hdd_ipa->ipa_p_rx_packets = 0;
5403 hdd_ipa->resource_loading = false;
5404 hdd_ipa->resource_unloading = false;
5405 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005406 hdd_ipa->ipa_pipes_down = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005407 /* Setup IPA sys_pipe for MCC */
5408 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5409 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5410 if (ret)
5411 goto fail_create_sys_pipe;
5412 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005413 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5414 goto fail_create_sys_pipe;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005415 } else {
5416 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5417 if (ret)
5418 goto fail_create_sys_pipe;
5419 }
5420
Yun Parkbaa62862017-01-18 13:43:34 -08005421 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305422 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005423
5424fail_create_sys_pipe:
5425 hdd_ipa_destroy_rm_resource(hdd_ipa);
5426fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305427 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305428 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005429 hdd_ctx->hdd_ipa = NULL;
5430 ghdd_ipa = NULL;
5431fail_return:
Yun Parkbaa62862017-01-18 13:43:34 -08005432 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305433 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005434}
5435
5436/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005437 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5438 * @hdd_ctx: HDD global context
5439 *
5440 * Allocate hdd_ipa resources, ipa pipe resource and register
5441 * wlan interface with IPA module.
5442 *
5443 * Return: QDF_STATUS enumeration
5444 */
5445QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
5446{
5447 QDF_STATUS ret;
5448
5449 cds_ssr_protect(__func__);
5450 ret = __hdd_ipa_init(hdd_ctx);
5451 cds_ssr_unprotect(__func__);
5452
5453 return ret;
5454}
5455
Arun Khandavallicc544b32017-01-30 19:52:16 +05305456
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005457/**
Yun Parkf19e07d2015-11-20 11:34:27 -08005458 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
5459 * @hdd_ipa: pointer to HDD IPA struct
5460 *
5461 * Return: none
5462 */
Jeff Johnsond7720632016-10-05 16:04:32 -07005463static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08005464{
5465 struct ipa_uc_pending_event *pending_event = NULL;
5466
Anurag Chouhanffb21542016-02-17 14:33:03 +05305467 while (qdf_list_remove_front(&hdd_ipa->pending_event,
5468 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305469 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005470 }
5471
Anurag Chouhanffb21542016-02-17 14:33:03 +05305472 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005473}
5474
5475/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005476 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005477 * @hdd_ctx: HDD global context
5478 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305479 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005480 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005481static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005482{
5483 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5484 int i;
5485 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305486 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005487 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5488
5489 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305490 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005491
5492 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5493 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5494 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5495 }
5496
5497 /* Teardown IPA sys_pipe for MCC */
5498 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5499 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5500
5501 hdd_ipa_destroy_rm_resource(hdd_ipa);
5502
5503#ifdef WLAN_OPEN_SOURCE
5504 cancel_work_sync(&hdd_ipa->pm_work);
5505#endif
5506
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305507 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005508
Nirav Shahcbc6d722016-03-01 16:24:53 +05305509 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5510 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305511 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005512
5513 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
5514 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
5515
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305516 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005517 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305518 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005519
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305520 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005521
5522 /* destory the interface lock */
5523 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5524 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305525 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005526 }
5527
5528 /* This should never hit but still make sure that there are no pending
5529 * descriptor in IPA hardware
5530 */
5531 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305532 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005533 "IPA Pending write done: %d Waiting!",
5534 hdd_ipa->pending_hw_desc_cnt);
5535
5536 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
5537 usleep_range(100, 100);
5538 }
5539
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305540 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005541 "IPA Pending write done: desc: %d %s(%d)!",
5542 hdd_ipa->pending_hw_desc_cnt,
5543 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
5544 : "leak", i);
5545 }
5546 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08005547 if (ipa_uc_dereg_rdyCB())
5548 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5549 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005550 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005551 if (true == hdd_ipa->uc_loaded) {
5552 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305553 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
5554 __func__, hdd_ipa->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005555 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
5556 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305557 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
5558 __func__, hdd_ipa->rx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005559 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
5560 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305561 qdf_mutex_destroy(&hdd_ipa->event_lock);
5562 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005563 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005564
5565#ifdef WLAN_OPEN_SOURCE
5566 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5567 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5568 hdd_ipa->uc_op_work[i].msg = NULL;
5569 }
5570#endif
5571 }
5572
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305573 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005574 hdd_ctx->hdd_ipa = NULL;
5575
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305576 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005577}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005578
5579/**
5580 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5581 * @hdd_ctx: HDD global context
5582 *
5583 * Return: QDF_STATUS enumeration
5584 */
5585QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
5586{
5587 QDF_STATUS ret;
5588
5589 cds_ssr_protect(__func__);
5590 ret = __hdd_ipa_cleanup(hdd_ctx);
5591 cds_ssr_unprotect(__func__);
5592
5593 return ret;
5594}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005595#endif /* IPA_OFFLOAD */