blob: ffde0d669afee0fb7034d50fa858d39c8c64e7f6 [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 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302321static QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002322{
2323 struct ipa_wdi_in_params pipe_in;
2324 struct ipa_wdi_out_params pipe_out;
2325 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2326 p_cds_contextType cds_ctx = hdd_ctx->pcds_context;
2327 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07002328 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002330 qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params));
2331 qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302332 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
2333 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002334
Anurag Chouhanffb21542016-02-17 14:33:03 +05302335 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302336
2337 if (!cds_is_driver_recovering()) {
2338 qdf_mutex_create(&ipa_ctxt->event_lock);
2339 qdf_mutex_create(&ipa_ctxt->ipa_lock);
2340 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002341
2342 /* TX PIPE */
2343 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2344 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
2345 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2346 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2347 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
2348 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
2349 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2350 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
2351 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
2352 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
2353 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2354 pipe_in.sys.notify = hdd_ipa_i2w_cb;
2355 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302356 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002357 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
2358 pipe_in.sys.keep_ipa_awake = true;
2359 }
2360
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002361 pipe_in.u.dl.comp_ring_base_pa =
2362 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002363 pipe_in.u.dl.comp_ring_size =
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002364 ipa_ctxt->ipa_resource.tx_comp_ring_size *
2365 sizeof(qdf_dma_addr_t);
2366 pipe_in.u.dl.ce_ring_base_pa =
2367 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
2368 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
2369 pipe_in.u.dl.ce_ring_size =
2370 ipa_ctxt->ipa_resource.ce_sr_ring_size;
2371 pipe_in.u.dl.num_tx_buffers =
2372 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002374 qdf_mem_copy(&ipa_ctxt->cons_pipe_in,
2375 &pipe_in,
2376 sizeof(struct ipa_wdi_in_params));
2377 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr,
2378 IPA_CLIENT_WLAN1_CONS);
2379 if (true == ipa_ctxt->uc_loaded) {
2380 /* Connect WDI IPA PIPE */
2381 ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out);
2382 /* Micro Controller Doorbell register */
2383 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2384 "%s CONS DB pipe out 0x%x",
2385 __func__, (unsigned int)pipe_out.uc_door_bell_pa);
2386
2387 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
2388 /* WLAN TX PIPE Handle */
2389 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
2390 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2391 "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x, CERZ %d, NB %d, CDBPAD 0x%x",
2392 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
2393 pipe_in.u.dl.comp_ring_size,
2394 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
2395 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
2396 pipe_in.u.dl.ce_ring_size,
2397 pipe_in.u.dl.num_tx_buffers,
2398 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
2399 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002400
2401 /* RX PIPE */
2402 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2403 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
2404 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
2405 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
2406 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
2407 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
2408 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
2409 sizeof(struct sps_iovec);
2410 pipe_in.sys.notify = hdd_ipa_w2i_cb;
2411 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302412 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002413 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
2414 pipe_in.sys.keep_ipa_awake = true;
2415 }
2416
Dhanashri Atreb08959a2016-03-01 17:28:03 -08002417 pipe_in.u.ul.rdy_ring_base_pa =
2418 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
2419 pipe_in.u.ul.rdy_ring_size =
2420 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
2421 pipe_in.u.ul.rdy_ring_rp_pa =
2422 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002423 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002424 qdf_mem_copy(&ipa_ctxt->prod_pipe_in,
2425 &pipe_in,
2426 sizeof(struct ipa_wdi_in_params));
2427 hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
2428 IPA_CLIENT_WLAN1_PROD);
2429 if (true == ipa_ctxt->uc_loaded) {
2430 ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out);
2431 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
2432 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
2433 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2434 "%s PROD DB pipe out 0x%x",
2435 __func__, (unsigned int)pipe_out.uc_door_bell_pa);
2436 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
2437 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
2438 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
2439 pipe_in.u.ul.rdy_ring_size,
2440 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
2441 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
2442 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002443
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002444 cdp_ipa_set_doorbell_paddr(soc,
2445 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
Leo Changfdb45c32016-10-28 11:09:23 -07002446 ipa_ctxt->tx_comp_doorbell_paddr,
2447 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002448
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08002449 cdp_ipa_register_op_cb(soc,
2450 (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx,
2451 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002452
2453 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08002454 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002455 hdd_ipa_uc_fw_op_event_handler);
2456 ipa_ctxt->uc_op_work[i].msg = NULL;
2457 }
2458
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302459 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002460}
2461
Leo Change3e49442015-10-26 20:07:13 -07002462/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002463 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07002464 * @hdd_ctx: hdd main context
2465 *
2466 * Force shutdown IPA pipe
2467 * Independent of FW pipe status, IPA pipe shutdonw progress
2468 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2469 * independent from FW pipe status
2470 *
2471 * Return: NONE
2472 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002473static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07002474{
2475 struct hdd_ipa_priv *hdd_ipa;
2476
2477 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
2478 return;
2479
2480 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2481 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302482 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07002483 "IPA pipes are not down yet, force shutdown");
2484 hdd_ipa_uc_disable_pipes(hdd_ipa);
2485 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302486 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Leo Change3e49442015-10-26 20:07:13 -07002487 "IPA pipes are down, do nothing");
2488 }
2489
2490 return;
2491}
2492
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002493/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002494 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
2495 * __hdd_ipa_uc_force_pipe_shutdown
2496 * @hdd_ctx: hdd main context
2497 *
2498 * Force shutdown IPA pipe
2499 * Independent of FW pipe status, IPA pipe shutdonw progress
2500 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2501 * independent from FW pipe status
2502 *
2503 * Return: NONE
2504 */
2505void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2506{
2507 cds_ssr_protect(__func__);
2508 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2509 cds_ssr_unprotect(__func__);
2510}
2511
2512/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302513 * hdd_ipa_msg_free_fn() - Free an IPA message
2514 * @buff: pointer to the IPA message
2515 * @len: length of the IPA message
2516 * @type: type of IPA message
2517 *
2518 * Return: None
2519 */
2520static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2521{
2522 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "msg type:%d, len:%d", type, len);
2523 ghdd_ipa->stats.num_free_msg++;
2524 qdf_mem_free(buff);
2525}
2526
Govind Singh9c58eba2016-09-02 16:23:06 +05302527/**
jge62037862016-12-09 10:44:33 +08002528 * hdd_ipa_uc_send_evt() - send event to ipa
2529 * @hdd_ctx: pointer to hdd context
2530 * @type: event type
2531 * @mac_addr: pointer to mac address
2532 *
2533 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05302534 *
2535 * Return: 0 - Success
2536 */
jge62037862016-12-09 10:44:33 +08002537static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter,
2538 enum ipa_wlan_event type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05302539{
jge62037862016-12-09 10:44:33 +08002540 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Govind Singh9c58eba2016-09-02 16:23:06 +05302541 struct ipa_msg_meta meta;
2542 struct ipa_wlan_msg *msg;
2543 int ret = 0;
jge62037862016-12-09 10:44:33 +08002544
2545 meta.msg_len = sizeof(struct ipa_wlan_msg);
2546 msg = qdf_mem_malloc(meta.msg_len);
2547 if (msg == NULL) {
2548 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2549 "msg allocation failed");
2550 return -ENOMEM;
2551 }
2552
2553 meta.msg_type = type;
2554 strlcpy(msg->name, adapter->dev->name,
2555 IPA_RESOURCE_NAME_MAX);
2556 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
2557 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
2558 msg->name, meta.msg_type);
2559 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2560 if (ret) {
2561 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2562 "%s: Evt: %d fail:%d",
2563 msg->name, meta.msg_type, ret);
2564 qdf_mem_free(msg);
2565 return ret;
2566 }
2567
2568 hdd_ipa->stats.num_send_msg++;
2569
2570 return ret;
2571}
2572
2573/**
2574 * hdd_ipa_uc_disconnect_client() - send client disconnect event
2575 * @hdd_ctx: pointer to hdd adapter
2576 *
2577 * Send disconnect client event to IPA driver during SSR
2578 *
2579 * Return: 0 - Success
2580 */
2581static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter)
2582{
2583 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2584 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05302585 int i;
2586
2587 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2588 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2589 continue;
2590 if ((adapter->aStaInfo[i].isUsed) &&
jge62037862016-12-09 10:44:33 +08002591 (!adapter->aStaInfo[i].isDeauthInProgress) &&
2592 hdd_ipa->sap_num_connected_sta) {
2593 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
2594 adapter->aStaInfo[i].macAddrSTA.bytes);
2595 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05302596 }
2597 }
2598
2599 return ret;
2600}
2601
2602/**
jge62037862016-12-09 10:44:33 +08002603 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
2604 * @hdd_ctx: pointer to hdd adapter
2605 *
2606 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05302607 *
2608 * Return: 0 - Success
2609 */
jge62037862016-12-09 10:44:33 +08002610
2611static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter)
2612{
2613 int ret = 0;
2614
2615 if (adapter->ipa_context)
2616 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
2617 adapter->dev->dev_addr);
2618
2619 return ret;
2620}
2621
2622#ifdef IPA_UC_STA_OFFLOAD
2623/**
2624 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
2625 * @hdd_ctx: pointer to hdd adapter
2626 *
2627 * Send disconnect sta event to IPA driver during SSR
2628 *
2629 * Return: 0 - Success
2630 */
2631static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2632{
2633 hdd_station_ctx_t *pHddStaCtx;
2634 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2635 int ret = 0;
2636
2637 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa) &&
2638 hdd_ipa->sta_connected) {
2639 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2640 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
2641 pHddStaCtx->conn_info.bssId);
2642 }
2643
2644 return ret;
2645}
2646#else
2647static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter)
2648{
2649 return 0;
2650}
2651
2652#endif
2653
2654/**
2655 * hdd_ipa_uc_disconnect() - send disconnect ipa event
2656 * @hdd_ctx: pointer to hdd context
2657 *
2658 * Send disconnect event to IPA driver during SSR
2659 *
2660 * Return: 0 - Success
2661 */
2662static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05302663{
2664 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2665 QDF_STATUS status;
2666 hdd_adapter_t *adapter;
2667 int ret = 0;
2668
Govind Singh9c58eba2016-09-02 16:23:06 +05302669 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2670 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2671 adapter = adapter_node->pAdapter;
jge62037862016-12-09 10:44:33 +08002672 if (adapter->device_mode == QDF_SAP_MODE) {
2673 hdd_ipa_uc_disconnect_client(adapter);
2674 hdd_ipa_uc_disconnect_ap(adapter);
2675 } else if (adapter->device_mode == QDF_STA_MODE) {
2676 hdd_ipa_uc_disconnect_sta(adapter);
2677 }
2678
Govind Singh9c58eba2016-09-02 16:23:06 +05302679 status = hdd_get_next_adapter(
2680 hdd_ctx, adapter_node, &next);
2681 adapter_node = next;
2682 }
2683
2684 return ret;
2685}
2686
2687/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002688 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002689 *
2690 * Deinit basic IPA UC host side to be in sync reloaded FW during
2691 * SSR
2692 *
2693 * Return: 0 - Success
2694 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002695static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002696{
2697 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2698 int idx;
2699 struct hdd_ipa_iface_context *iface_context;
Arun Khandavallicc544b32017-01-30 19:52:16 +05302700 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002701
Arun Khandavallicc544b32017-01-30 19:52:16 +05302702 if (!hdd_ipa)
2703 return 0;
2704
2705 hdd_ctx = hdd_ipa->hdd_ctx;
2706 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002707 return 0;
2708
jge62037862016-12-09 10:44:33 +08002709 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302710 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08002711
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002712 /* Clean up HDD IPA interfaces */
2713 for (idx = 0; (hdd_ipa->num_iface > 0) &&
2714 (idx < HDD_IPA_MAX_IFACE); idx++) {
2715 iface_context = &hdd_ipa->iface_context[idx];
2716 if (iface_context && iface_context->adapter)
2717 hdd_ipa_cleanup_iface(iface_context);
2718 }
2719
2720 /* After SSR, wlan driver reloads FW again. But we need to protect
2721 * IPA submodule during SSR transient state. So deinit basic IPA
2722 * UC host side to be in sync with reloaded FW during SSR
2723 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08002724 if (!hdd_ipa->ipa_pipes_down)
2725 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002726
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302727 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002728 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2729 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
2730 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
2731 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302732 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002733
Arun Khandavallicc544b32017-01-30 19:52:16 +05302734 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2735 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
2736 __func__, hdd_ipa->tx_pipe_handle);
2737 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
2738
2739 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
2740 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
2741 __func__, hdd_ipa->rx_pipe_handle);
2742 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
2743
Guolei Bianca144d82016-11-10 11:07:42 +08002744 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
2745 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
2746
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002747 /* Full IPA driver cleanup not required since wlan driver is now
2748 * unloaded and reloaded after SSR.
2749 */
2750 return 0;
2751}
2752
2753/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002754 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
2755 *
2756 * Deinit basic IPA UC host side to be in sync reloaded FW during
2757 * SSR
2758 *
2759 * Return: 0 - Success
2760 */
2761int hdd_ipa_uc_ssr_deinit(void)
2762{
2763 int ret;
2764
2765 cds_ssr_protect(__func__);
2766 ret = __hdd_ipa_uc_ssr_deinit();
2767 cds_ssr_unprotect(__func__);
2768
2769 return ret;
2770}
2771
2772/**
2773 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002774 *
2775 * Init basic IPA UC host side to be in sync with reloaded FW after
2776 * SSR to resume IPA UC operations
2777 *
2778 * Return: 0 - Success
2779 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302780static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002781{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002782
Arun Khandavallicc544b32017-01-30 19:52:16 +05302783 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2784 int i;
2785 struct hdd_ipa_iface_context *iface_context = NULL;
2786 struct ol_txrx_pdev_t *pdev = NULL;
2787
2788 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
2789 return 0;
2790
2791 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2792 if (!pdev) {
2793 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
2794 return -EINVAL;
2795 }
2796
2797 cdp_ipa_get_resource(cds_get_context(QDF_MODULE_ID_SOC),
2798 cds_get_context(QDF_MODULE_ID_TXRX),
2799 &hdd_ipa->ipa_resource);
2800 if ((hdd_ipa->ipa_resource.ce_sr_base_paddr == 0) ||
2801 (hdd_ipa->ipa_resource.tx_comp_ring_base_paddr == 0) ||
2802 (hdd_ipa->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
2803 (hdd_ipa->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
2804 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2805 "IPA UC resource alloc fail");
2806 return -EINVAL;
2807 }
2808
2809 /* Create the interface context */
2810 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2811 iface_context = &hdd_ipa->iface_context[i];
2812 iface_context->hdd_ipa = hdd_ipa;
2813 iface_context->cons_client =
2814 hdd_ipa_adapter_2_client[i].cons_client;
2815 iface_context->prod_client =
2816 hdd_ipa_adapter_2_client[i].prod_client;
2817 iface_context->iface_id = i;
2818 iface_context->adapter = NULL;
2819 }
2820 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
2821 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
2822 hdd_ipa->vdev_offload_enabled[i] = false;
2823 }
2824
2825 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2826 hdd_ipa->resource_loading = false;
2827 hdd_ipa->resource_unloading = false;
2828 hdd_ipa->sta_connected = 0;
2829 hdd_ipa->ipa_pipes_down = true;
2830 hdd_ipa->uc_loaded = true;
2831
2832 if (hdd_ipa_uc_ol_init(hdd_ctx)) {
2833 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
2834 "Failed to setup pipes");
2835 return -EINVAL;
2836 }
2837
2838 }
2839
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002840 return 0;
2841}
Leo Chang3bc8fed2015-11-13 10:59:47 -08002842
2843/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002844 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
2845 *
2846 * Init basic IPA UC host side to be in sync with reloaded FW after
2847 * SSR to resume IPA UC operations
2848 *
2849 * Return: 0 - Success
2850 */
Arun Khandavallicc544b32017-01-30 19:52:16 +05302851int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002852{
2853 int ret;
2854
2855 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05302856 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002857 cds_ssr_unprotect(__func__);
2858
2859 return ret;
2860}
2861
2862/**
2863 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08002864 * @hdd_ctx: Global HDD context
2865 * @skb: skb sent to IPA
2866 * @session_id: send packet instance session id
2867 *
2868 * Send TX packet which generated by system to IPA.
2869 * This routine only will be used for function verification
2870 *
2871 * Return: NULL packet sent to IPA properly
2872 * NULL invalid packet drop
2873 * skb packet not sent to IPA. legacy data path should handle
2874 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002875static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002876 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07002877{
Leo Chang3bc8fed2015-11-13 10:59:47 -08002878 struct ipa_header *ipa_header;
2879 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002880 struct hdd_ipa_priv *hdd_ipa;
2881
2882 if (wlan_hdd_validate_context(hdd_ctx))
2883 return skb;
2884
2885 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002886
2887 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2888 return skb;
2889
Leo Chang07b28f62016-05-11 12:29:22 -07002890 if (!hdd_ipa)
2891 return skb;
2892
2893 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
2894 return skb;
2895
Leo Changcc923e22016-06-16 15:29:03 -07002896 if (skb_headroom(skb) <
2897 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07002898 return skb;
2899
Leo Chang3bc8fed2015-11-13 10:59:47 -08002900 ipa_header = (struct ipa_header *) skb_push(skb,
2901 sizeof(struct ipa_header));
2902 if (!ipa_header) {
2903 /* No headroom, legacy */
2904 return skb;
2905 }
2906 memset(ipa_header, 0, sizeof(*ipa_header));
2907 ipa_header->vdev_id = 0;
2908
2909 frag_header = (struct frag_header *) skb_push(skb,
2910 sizeof(struct frag_header));
2911 if (!frag_header) {
2912 /* No headroom, drop */
2913 kfree_skb(skb);
2914 return NULL;
2915 }
2916 memset(frag_header, 0, sizeof(*frag_header));
2917 frag_header->length = skb->len - sizeof(struct frag_header)
2918 - sizeof(struct ipa_header);
2919
2920 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
2921 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07002922}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002923
2924/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002925 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
2926 * @hdd_ctx: Global HDD context
2927 * @skb: skb sent to IPA
2928 * @session_id: send packet instance session id
2929 *
2930 * Send TX packet which generated by system to IPA.
2931 * This routine only will be used for function verification
2932 *
2933 * Return: NULL packet sent to IPA properly
2934 * NULL invalid packet drop
2935 * skb packet not sent to IPA. legacy data path should handle
2936 */
2937struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
2938 struct sk_buff *skb, uint8_t session_id)
2939{
2940 struct sk_buff *ret;
2941
2942 cds_ssr_protect(__func__);
2943 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
2944 cds_ssr_unprotect(__func__);
2945
2946 return ret;
2947}
2948
2949/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002950 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
2951 * @work: scheduled work
2952 *
2953 * When IPA resources are released in hdd_ipa_rm_try_release() we do
2954 * not want to immediately release the wake lock since the system
2955 * would then potentially try to suspend when there is a healthy data
2956 * rate. Deferred work is scheduled and this function handles the
2957 * work. When this function is called, if the IPA resource is still
2958 * released then we release the wake lock.
2959 *
2960 * Return: None
2961 */
2962static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
2963{
2964 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
2965 struct hdd_ipa_priv,
2966 wake_lock_work);
2967
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302968 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002969
2970 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
2971 goto end;
2972
2973 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302974 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002975 WIFI_POWER_EVENT_WAKELOCK_IPA);
2976
2977end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302978 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002979}
2980
2981/**
2982 * hdd_ipa_rm_request() - Request resource from IPA
2983 * @hdd_ipa: Global HDD IPA context
2984 *
2985 * Return: 0 on success, negative errno on error
2986 */
2987static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
2988{
2989 int ret = 0;
2990
2991 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2992 return 0;
2993
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302994 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002995
2996 switch (hdd_ipa->rm_state) {
2997 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302998 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002999 return 0;
3000 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303001 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003002 return -EINPROGRESS;
3003 case HDD_IPA_RM_RELEASED:
3004 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3005 break;
3006 }
3007
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303008 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003009
3010 ret = ipa_rm_inactivity_timer_request_resource(
3011 IPA_RM_RESOURCE_WLAN_PROD);
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 if (ret == 0) {
3015 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3016 hdd_ipa->stats.num_rm_grant_imm++;
3017 }
3018
3019 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3020 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303021 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003022 WIFI_POWER_EVENT_WAKELOCK_IPA);
3023 hdd_ipa->wake_lock_released = false;
3024 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303025 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003026
3027 return ret;
3028}
3029
3030/**
3031 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3032 * @hdd_ipa: Global HDD IPA context
3033 *
3034 * Return: 0 if resources released, negative errno otherwise
3035 */
3036static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3037{
3038 int ret = 0;
3039
3040 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3041 return 0;
3042
3043 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3044 return -EAGAIN;
3045
3046 spin_lock_bh(&hdd_ipa->q_lock);
3047 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
3048 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
3049 spin_unlock_bh(&hdd_ipa->q_lock);
3050 return -EAGAIN;
3051 }
3052 spin_unlock_bh(&hdd_ipa->q_lock);
3053
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303054 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055
Nirav Shahcbc6d722016-03-01 16:24:53 +05303056 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303057 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003058 return -EAGAIN;
3059 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303060 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003061
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303062 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003063 switch (hdd_ipa->rm_state) {
3064 case HDD_IPA_RM_GRANTED:
3065 break;
3066 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303067 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003068 return -EINPROGRESS;
3069 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303070 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003071 return 0;
3072 }
3073
3074 /* IPA driver returns immediately so set the state here to avoid any
3075 * race condition.
3076 */
3077 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3078 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303079 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003080
3081 ret =
3082 ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
3083
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303084 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003085 if (unlikely(ret != 0)) {
3086 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3087 WARN_ON(1);
3088 }
3089
3090 /*
3091 * If wake_lock is released immediately, kernel would try to suspend
3092 * immediately as well, Just avoid ping-pong between suspend-resume
3093 * while there is healthy amount of data transfer going on by
3094 * releasing the wake_lock after some delay.
3095 */
3096 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3097 msecs_to_jiffies
3098 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3099
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303100 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101
3102 return ret;
3103}
3104
3105/**
3106 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3107 * @user_data: user data registered with IPA
3108 * @event: the IPA resource manager event that occurred
3109 * @data: the data associated with the event
3110 *
3111 * Return: None
3112 */
3113static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
3114 unsigned long data)
3115{
3116 struct hdd_ipa_priv *hdd_ipa = user_data;
3117
3118 if (unlikely(!hdd_ipa))
3119 return;
3120
3121 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3122 return;
3123
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303124 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003125
3126 switch (event) {
3127 case IPA_RM_RESOURCE_GRANTED:
3128 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3129 /* RM Notification comes with ISR context
3130 * it should be serialized into work queue to avoid
3131 * ISR sleep problem
3132 */
3133 hdd_ipa->uc_rm_work.event = event;
3134 schedule_work(&hdd_ipa->uc_rm_work.work);
3135 break;
3136 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303137 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003138 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303139 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003140 hdd_ipa->stats.num_rm_grant++;
3141 break;
3142
3143 case IPA_RM_RESOURCE_RELEASED:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303144 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003145 hdd_ipa->resource_unloading = false;
3146 break;
3147
3148 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303149 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003150 break;
3151 }
3152}
3153
3154/**
3155 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3156 *
3157 * Callback function registered with IPA that is called when IPA wants
3158 * to release the WLAN consumer resource
3159 *
3160 * Return: 0 if the request is granted, negative errno otherwise
3161 */
3162static int hdd_ipa_rm_cons_release(void)
3163{
3164 return 0;
3165}
3166
3167/**
3168 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3169 *
3170 * Callback function registered with IPA that is called when IPA wants
3171 * to access the WLAN consumer resource
3172 *
3173 * Return: 0 if the request is granted, negative errno otherwise
3174 */
3175static int hdd_ipa_rm_cons_request(void)
3176{
Yun Park4d8b60a2015-10-22 13:59:32 -07003177 int ret = 0;
3178
3179 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303180 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003181 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003182 __func__);
3183 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003184 ret = -EINPROGRESS;
3185 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303186 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07003187 "%s: IPA resource unloading in progress",
3188 __func__);
3189 ghdd_ipa->pending_cons_req = true;
3190 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003191 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003192
3193 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003194}
3195
3196/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003197 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003198 * @hdd_ctx: Global HDD context
3199 * @tx_packets: Number of packets transmitted in the last sample period
3200 * @rx_packets: Number of packets received in the last sample period
3201 *
3202 * Return: 0 on success, negative errno on error
3203 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003204static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003205 uint64_t rx_packets)
3206{
3207 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003208 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003209 struct ipa_rm_perf_profile profile;
3210 int ret;
3211
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003212 if (wlan_hdd_validate_context(hdd_ctx))
3213 return 0;
3214
3215 hdd_ipa = hdd_ctx->hdd_ipa;
3216
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003217 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3218 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3219 return 0;
3220
3221 memset(&profile, 0, sizeof(profile));
3222
3223 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3224 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3225 else if (tx_packets >
3226 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3227 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3228 else
3229 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3230
3231 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3232 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3233 else if (rx_packets >
3234 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3235 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3236 else
3237 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3238
Yun Park8f289c82016-10-18 16:38:21 -07003239 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003240 "CONS perf curr: %d, next: %d",
3241 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Park8f289c82016-10-18 16:38:21 -07003242 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003243 "PROD perf curr: %d, next: %d",
3244 hdd_ipa->curr_prod_bw, next_prod_bw);
3245
3246 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003247 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003248 hdd_ipa->curr_cons_bw, next_cons_bw);
3249 profile.max_supported_bandwidth_mbps = next_cons_bw;
3250 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
3251 &profile);
3252 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003253 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003254
3255 return ret;
3256 }
3257 hdd_ipa->curr_cons_bw = next_cons_bw;
3258 hdd_ipa->stats.num_cons_perf_req++;
3259 }
3260
3261 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003262 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003263 hdd_ipa->curr_prod_bw, next_prod_bw);
3264 profile.max_supported_bandwidth_mbps = next_prod_bw;
3265 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
3266 &profile);
3267 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003268 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003269 return ret;
3270 }
3271 hdd_ipa->curr_prod_bw = next_prod_bw;
3272 hdd_ipa->stats.num_prod_perf_req++;
3273 }
3274
3275 return 0;
3276}
3277
3278/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003279 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3280 * @hdd_ctx: Global HDD context
3281 * @tx_packets: Number of packets transmitted in the last sample period
3282 * @rx_packets: Number of packets received in the last sample period
3283 *
3284 * Return: 0 on success, negative errno on error
3285 */
3286int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
3287 uint64_t rx_packets)
3288{
3289 int ret;
3290
3291 cds_ssr_protect(__func__);
3292 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3293 cds_ssr_unprotect(__func__);
3294
3295 return ret;
3296}
3297
3298/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003299 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3300 * @work: struct work_struct
3301 * @work_handler: work_handler
3302 *
3303 * Return: none
3304 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003305static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3306 work_func_t work_handler)
3307{
3308 INIT_WORK(work, work_handler);
3309}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003310
3311/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003312 * hdd_ipa_setup_rm() - Setup IPA resource management
3313 * @hdd_ipa: Global HDD IPA context
3314 *
3315 * Return: 0 on success, negative errno on error
3316 */
3317static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3318{
3319 struct ipa_rm_create_params create_params = { 0 };
3320 int ret;
3321
3322 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3323 return 0;
3324
Rajeev Kumar217f2172016-01-06 18:11:55 -08003325 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3326 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003327 memset(&create_params, 0, sizeof(create_params));
3328 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
3329 create_params.reg_params.user_data = hdd_ipa;
3330 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
3331 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3332
3333 ret = ipa_rm_create_resource(&create_params);
3334 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303335 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003336 "Create RM resource failed: %d", ret);
3337 goto setup_rm_fail;
3338 }
3339
3340 memset(&create_params, 0, sizeof(create_params));
3341 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
3342 create_params.request_resource = hdd_ipa_rm_cons_request;
3343 create_params.release_resource = hdd_ipa_rm_cons_release;
3344 create_params.floor_voltage = IPA_VOLTAGE_SVS;
3345
3346 ret = ipa_rm_create_resource(&create_params);
3347 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303348 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003349 "Create RM CONS resource failed: %d", ret);
3350 goto delete_prod;
3351 }
3352
3353 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3354 IPA_RM_RESOURCE_APPS_CONS);
3355
3356 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3357 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
3358 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303359 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003360 ret);
3361 goto timer_init_failed;
3362 }
3363
3364 /* Set the lowest bandwidth to start with */
3365 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
3366
3367 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303368 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003369 "Set perf level failed: %d", ret);
3370 goto set_perf_failed;
3371 }
3372
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303373 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003374 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
3375 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303376 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003377 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3378 hdd_ipa->wake_lock_released = true;
3379 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
3380
3381 return ret;
3382
3383set_perf_failed:
3384 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3385
3386timer_init_failed:
3387 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3388
3389delete_prod:
3390 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3391
3392setup_rm_fail:
3393 return ret;
3394}
3395
3396/**
3397 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
3398 * @hdd_ipa: Global HDD IPA context
3399 *
3400 * Destroys all resources associated with the IPA resource manager
3401 *
3402 * Return: None
3403 */
3404static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
3405{
3406 int ret;
3407
3408 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3409 return;
3410
3411 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303412 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413
3414#ifdef WLAN_OPEN_SOURCE
3415 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
3416#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303417 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418
3419 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
3420
3421 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
3422 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303423 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003424 "RM PROD resource delete failed %d", ret);
3425
3426 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
3427 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303428 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003429 "RM CONS resource delete failed %d", ret);
3430}
3431
3432/**
3433 * hdd_ipa_send_skb_to_network() - Send skb to kernel
3434 * @skb: network buffer
3435 * @adapter: network adapter
3436 *
3437 * Called when a network buffer is received which should not be routed
3438 * to the IPA module.
3439 *
3440 * Return: None
3441 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303442static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003443 hdd_adapter_t *adapter)
3444{
3445 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3446 unsigned int cpu_index;
3447
3448 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303449 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003450 adapter);
3451 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003452 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003453 return;
3454 }
3455
Prashanth Bhatta9e143052015-12-04 11:56:47 -08003456 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003458 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003459 return;
3460 }
3461
3462 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
3463 skb->dev = adapter->dev;
3464 skb->protocol = eth_type_trans(skb, skb->dev);
3465 skb->ip_summed = CHECKSUM_NONE;
3466
3467 cpu_index = wlan_hdd_get_cpu();
3468
3469 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
3470 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
3471 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
3472 else
3473 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
3474
3475 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
3476 adapter->dev->last_rx = jiffies;
3477}
3478
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479/**
Leo Chang69c39692016-10-12 20:11:12 -07003480 * hdd_ipa_forward() - handle packet forwarding to wlan tx
3481 * @hdd_ipa: pointer to hdd ipa context
3482 * @adapter: network adapter
3483 * @skb: data pointer
3484 *
3485 * if exception packet has set forward bit, copied new packet should be
3486 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
3487 * put into pm queue and tx procedure will be differed
3488 *
3489 * Return: None
3490 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07003491static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
3492 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07003493{
Leo Chang69c39692016-10-12 20:11:12 -07003494 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
3495
Leo Chang69c39692016-10-12 20:11:12 -07003496 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
3497 /* WLAN subsystem is in suspend, put int queue */
3498 if (hdd_ipa->suspended) {
3499 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3500 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3501 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003502 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
3503 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07003504 pm_tx_cb->exception = true;
3505 pm_tx_cb->adapter = adapter;
3506 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003507 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07003508 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
3509 hdd_ipa->stats.num_tx_queued++;
3510 } else {
3511 /* Resume, put packet into WLAN TX */
3512 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003513 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07003514 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3515 "packet tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08003516 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07003517 } else {
Yun Parkb187d542016-11-14 18:10:04 -08003518 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07003519 hdd_ipa->ipa_tx_forward++;
3520 }
3521 }
3522}
3523
3524/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003525 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
3526 * @hdd_ipa: pointer to HDD IPA struct
3527 * @adapter: hdd adapter pointer
3528 * @desc: Firmware descriptor
3529 * @skb: Data buffer
3530 *
3531 * Return:
3532 * HDD_IPA_FORWARD_PKT_NONE
3533 * HDD_IPA_FORWARD_PKT_DISCARD
3534 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
3535 *
3536 */
3537
3538static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
3539 struct hdd_ipa_priv *hdd_ipa,
3540 hdd_adapter_t *adapter,
3541 uint8_t desc,
3542 qdf_nbuf_t skb)
3543{
3544 int ret = HDD_IPA_FORWARD_PKT_NONE;
3545
3546 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303547 if (!ol_txrx_fwd_desc_thresh_check(
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003548 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(
3549 adapter->sessionId))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05303550 /* Drop the packet*/
3551 hdd_ipa->stats.num_tx_fwd_err++;
3552 kfree_skb(skb);
3553 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3554 return ret;
3555 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003556 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3557 "Forward packet to Tx (fw_desc=%d)", desc);
3558 hdd_ipa->ipa_tx_forward++;
3559
3560 if ((desc & FW_RX_DESC_DISCARD_M)) {
3561 hdd_ipa_forward(hdd_ipa, adapter, skb);
3562 hdd_ipa->ipa_rx_internel_drop_count++;
3563 hdd_ipa->ipa_rx_discard++;
3564 ret = HDD_IPA_FORWARD_PKT_DISCARD;
3565 } else {
3566 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
3567 if (cloned_skb)
3568 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
3569 else
3570 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3571 "%s: tx skb alloc failed",
3572 __func__);
3573 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
3574 }
3575 }
3576
3577 return ret;
3578}
3579
3580/**
Leo Chang69c39692016-10-12 20:11:12 -07003581 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003582 * @priv: pointer to private data registered with IPA (we register a
3583 * pointer to the global IPA context)
3584 * @evt: the IPA event which triggered the callback
3585 * @data: data associated with the event
3586 *
3587 * Return: None
3588 */
Yun Parkf8d6a122016-10-11 15:49:43 -07003589static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590 unsigned long data)
3591{
3592 struct hdd_ipa_priv *hdd_ipa = NULL;
3593 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303594 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003595 uint8_t iface_id;
3596 uint8_t session_id;
3597 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003598 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07003599 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003600
3601 hdd_ipa = (struct hdd_ipa_priv *)priv;
3602
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08003603 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
3604 return;
3605
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003606 switch (evt) {
3607 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05303608 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07003609
3610 /*
3611 * When SSR is going on or driver is unloading,
3612 * just drop the packets.
3613 */
3614 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
3615 if (0 != status) {
3616 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3617 "Invalid context: drop packet");
3618 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
3619 kfree_skb(skb);
3620 return;
3621 }
3622
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003623 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3624 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003625 iface_id = hdd_ipa->vdev_to_iface[session_id];
Govind Singhb6a89772016-08-12 11:23:35 +05303626 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003627 "IPA_RECEIVE: session_id=%u, iface_id=%u",
3628 session_id, iface_id);
3629 } else {
3630 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
3631 }
3632
3633 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303634 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003635 "IPA_RECEIVE: Invalid iface_id: %u",
3636 iface_id);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303637 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_INFO_HIGH,
Yun Parkb187d542016-11-14 18:10:04 -08003638 "w2i -- skb",
3639 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003640 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07003641 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003642 return;
3643 }
3644
3645 iface_context = &hdd_ipa->iface_context[iface_id];
3646 adapter = iface_context->adapter;
3647
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303648 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08003649 "w2i -- skb",
3650 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003651 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3652 hdd_ipa->stats.num_rx_excep++;
3653 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
3654 } else {
3655 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
3656 }
3657
3658 iface_context->stats.num_rx_ipa_excep++;
3659
3660 /* Disable to forward Intra-BSS Rx packets when
3661 * ap_isolate=1 in hostapd.conf
3662 */
Yun Park046101c2016-09-02 15:32:14 -07003663 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003664 /*
3665 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3666 * all Rx packets to IPA uC, which need to be forwarded
3667 * to other interface.
3668 * And, IPA driver will send back to WLAN host driver
3669 * through exception pipe with fw_desc field set by FW.
3670 * Here we are checking fw_desc field for FORWARD bit
3671 * set, and forward to Tx. Then copy to kernel stack
3672 * only when DISCARD bit is not set.
3673 */
3674 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003675 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3676 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3677 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003678 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003679 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303680 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003681 "Intra-BSS FWD is disabled-skip forward to Tx");
3682 }
3683
3684 hdd_ipa_send_skb_to_network(skb, adapter);
3685 break;
3686
3687 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303688 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003689 "w2i cb wrong event: 0x%x", evt);
3690 return;
3691 }
3692}
3693
3694/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003695 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3696 * @priv: pointer to private data registered with IPA (we register a
3697 * pointer to the global IPA context)
3698 * @evt: the IPA event which triggered the callback
3699 * @data: data associated with the event
3700 *
3701 * Return: None
3702 */
3703static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3704 unsigned long data)
3705{
3706 cds_ssr_protect(__func__);
3707 __hdd_ipa_w2i_cb(priv, evt, data);
3708 cds_ssr_unprotect(__func__);
3709}
3710
3711/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003712 * hdd_ipa_nbuf_cb() - IPA TX complete callback
3713 * @skb: packet buffer which was transmitted
3714 *
3715 * Return: None
3716 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303717void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003718{
3719 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3720
Govind Singhb6a89772016-08-12 11:23:35 +05303721 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05303722 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003723 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303724 ipa_free_skb((struct ipa_rx_data *)
3725 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003726
3727 hdd_ipa->stats.num_tx_comp_cnt++;
3728
3729 atomic_dec(&hdd_ipa->tx_ref_cnt);
3730
3731 hdd_ipa_rm_try_release(hdd_ipa);
3732}
3733
3734/**
3735 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
3736 * @iface_context: interface-specific IPA context
3737 * @ipa_tx_desc: packet data descriptor
3738 *
3739 * Return: None
3740 */
3741static void hdd_ipa_send_pkt_to_tl(
3742 struct hdd_ipa_iface_context *iface_context,
3743 struct ipa_rx_data *ipa_tx_desc)
3744{
3745 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003746 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303747 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003748
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303749 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003750 adapter = iface_context->adapter;
3751 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303752 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003753 ipa_free_skb(ipa_tx_desc);
3754 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303755 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003756 hdd_ipa_rm_try_release(hdd_ipa);
3757 return;
3758 }
3759
3760 /*
3761 * During CAC period, data packets shouldn't be sent over the air so
3762 * drop all the packets here
3763 */
3764 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
3765 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303766 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003767 iface_context->stats.num_tx_cac_drop++;
3768 hdd_ipa_rm_try_release(hdd_ipa);
3769 return;
3770 }
3771
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003772 ++adapter->stats.tx_packets;
3773
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303774 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003775
3776 skb = ipa_tx_desc->skb;
3777
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303778 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303779 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003780 /* FIXME: This is broken. No such field in cb any more:
Jeff Johnsonfaa63b82017-01-12 09:46:43 -08003781 * NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb;
3782 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003783 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05303784 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003785 ipa_tx_desc->dma_addr
3786 + HDD_IPA_WLAN_FRAG_HEADER
3787 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003788 ipa_tx_desc->skb->len -=
3789 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
3790 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05303791 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003792
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003793 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303794 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003795
3796 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
3797
Leo Changfdb45c32016-10-28 11:09:23 -07003798 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003799 (struct cdp_vdev *)iface_context->tl_context,
3800 ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003801 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303802 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003803 ipa_free_skb(ipa_tx_desc);
3804 iface_context->stats.num_tx_err++;
3805 hdd_ipa_rm_try_release(hdd_ipa);
3806 return;
3807 }
3808
3809 atomic_inc(&hdd_ipa->tx_ref_cnt);
3810
3811 iface_context->stats.num_tx++;
3812
3813}
3814
3815/**
Leo Chang11545d62016-10-17 14:53:50 -07003816 * hdd_ipa_is_present() - get IPA hw status
3817 * @hdd_ctx: pointer to hdd context
3818 *
3819 * ipa_uc_reg_rdyCB is not directly designed to check
3820 * ipa hw status. This is an undocumented function which
3821 * has confirmed with IPA team.
3822 *
3823 * Return: true - ipa hw present
3824 * false - ipa hw not present
3825 */
3826bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
3827{
3828 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07003829 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07003830 return true;
3831 else
3832 return false;
3833}
3834
3835/**
Leo Chang69c39692016-10-12 20:11:12 -07003836 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003837 * @work: pointer to the scheduled work
3838 *
3839 * Called during PM resume to send packets to TL which were queued
3840 * while host was in the process of suspending.
3841 *
3842 * Return: None
3843 */
Leo Chang69c39692016-10-12 20:11:12 -07003844static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003845{
3846 struct hdd_ipa_priv *hdd_ipa = container_of(work,
3847 struct hdd_ipa_priv,
3848 pm_work);
3849 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303850 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003851 uint32_t dequeued = 0;
3852
Leo Chang69c39692016-10-12 20:11:12 -07003853 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
3854 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303855 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303856 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
3857 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303858 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003859
3860 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003861 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07003862 if (pm_tx_cb->exception) {
3863 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3864 "FLUSH EXCEPTION");
3865 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
3866 } else {
3867 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003868 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07003869 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303870 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003871 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303872 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07003873 qdf_wake_lock_release(&hdd_ipa->wake_lock,
3874 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003875
3876 hdd_ipa->stats.num_tx_dequeued += dequeued;
3877 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
3878 hdd_ipa->stats.num_max_pm_queue = dequeued;
3879}
3880
3881/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003882 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003883 * @priv: pointer to private data registered with IPA (we register a
3884 * pointer to the interface-specific IPA context)
3885 * @evt: the IPA event which triggered the callback
3886 * @data: data associated with the event
3887 *
3888 * Return: None
3889 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003890static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003891 unsigned long data)
3892{
3893 struct hdd_ipa_priv *hdd_ipa = NULL;
3894 struct ipa_rx_data *ipa_tx_desc;
3895 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303896 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303898 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003899
Mukul Sharma81661ae2015-10-30 20:26:02 +05303900 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003901 ipa_tx_desc = (struct ipa_rx_data *)data;
3902 hdd_ipa = iface_context->hdd_ipa;
3903
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003904 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003905 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
3906 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003907 iface_context->stats.num_tx_drop++;
3908 return;
3909 }
3910
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003911 /*
3912 * When SSR is going on or driver is unloading, just drop the packets.
3913 * During SSR, there is no use in queueing the packets as STA has to
3914 * connect back any way
3915 */
3916 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303917 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918 ipa_free_skb(ipa_tx_desc);
3919 iface_context->stats.num_tx_drop++;
3920 return;
3921 }
3922
3923 skb = ipa_tx_desc->skb;
3924
Yun Parkb187d542016-11-14 18:10:04 -08003925 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
3926 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927
3928 /*
3929 * If PROD resource is not requested here then there may be cases where
3930 * IPA hardware may be clocked down because of not having proper
3931 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
3932 * workaround to request PROD resource while data is going over CONS
3933 * pipe to prevent the IPA hardware clockdown.
3934 */
3935 hdd_ipa_rm_request(hdd_ipa);
3936
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303937 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003938 /*
3939 * If host is still suspended then queue the packets and these will be
3940 * drained later when resume completes. When packet is arrived here and
3941 * host is suspended, this means that there is already resume is in
3942 * progress.
3943 */
3944 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303945 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003946 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
3947 pm_tx_cb->iface_context = iface_context;
3948 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303949 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003950 hdd_ipa->stats.num_tx_queued++;
3951
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303952 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003953 return;
3954 }
3955
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303956 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003957
3958 /*
3959 * If we are here means, host is not suspended, wait for the work queue
3960 * to finish.
3961 */
3962#ifdef WLAN_OPEN_SOURCE
3963 flush_work(&hdd_ipa->pm_work);
3964#endif
3965
3966 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
3967}
3968
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003969/*
3970 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
3971 * @priv: pointer to private data registered with IPA (we register a
3972 * pointer to the interface-specific IPA context)
3973 * @evt: the IPA event which triggered the callback
3974 * @data: data associated with the event
3975 *
3976 * Return: None
3977 */
3978static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
3979 unsigned long data)
3980{
3981 cds_ssr_protect(__func__);
3982 __hdd_ipa_i2w_cb(priv, evt, data);
3983 cds_ssr_unprotect(__func__);
3984}
3985
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003986/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003987 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003988 * @hdd_ctx: Global HDD context
3989 *
3990 * Return: 0 on success, negativer errno on error
3991 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003992static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003993{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003994 struct hdd_ipa_priv *hdd_ipa;
3995
3996 if (wlan_hdd_validate_context(hdd_ctx))
3997 return 0;
3998
3999 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004000
4001 if (!hdd_ipa_is_enabled(hdd_ctx))
4002 return 0;
4003
4004 /*
4005 * Check if IPA is ready for suspend, If we are here means, there is
4006 * high chance that suspend would go through but just to avoid any race
4007 * condition after suspend started, these checks are conducted before
4008 * allowing to suspend.
4009 */
4010 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4011 return -EAGAIN;
4012
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304013 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004014
4015 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304016 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004017 return -EAGAIN;
4018 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304019 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004020
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304021 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004022 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304023 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004024
4025 return 0;
4026}
4027
4028/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004029 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4030 * @hdd_ctx: Global HDD context
4031 *
4032 * Return: 0 on success, negativer errno on error
4033 */
4034int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
4035{
4036 int ret;
4037
4038 cds_ssr_protect(__func__);
4039 ret = __hdd_ipa_suspend(hdd_ctx);
4040 cds_ssr_unprotect(__func__);
4041
4042 return ret;
4043}
4044
4045/**
4046 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004047 * hdd_ctx: Global HDD context
4048 *
4049 * Return: 0 on success, negative errno on error
4050 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004051static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004052{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004053 struct hdd_ipa_priv *hdd_ipa;
4054
4055 if (wlan_hdd_validate_context(hdd_ctx))
4056 return 0;
4057
4058 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004059
4060 if (!hdd_ipa_is_enabled(hdd_ctx))
4061 return 0;
4062
4063 schedule_work(&hdd_ipa->pm_work);
4064
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304065 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004066 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304067 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004068
4069 return 0;
4070}
4071
4072/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004073 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4074 * hdd_ctx: Global HDD context
4075 *
4076 * Return: 0 on success, negative errno on error
4077 */
4078int hdd_ipa_resume(hdd_context_t *hdd_ctx)
4079{
4080 int ret;
4081
4082 cds_ssr_protect(__func__);
4083 ret = __hdd_ipa_resume(hdd_ctx);
4084 cds_ssr_unprotect(__func__);
4085
4086 return ret;
4087}
4088
4089/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004090 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
4091 * @hdd_ipa: Global HDD IPA context
4092 *
4093 * Return: 0 on success, negative errno on error
4094 */
4095static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4096{
4097 int i, ret = 0;
4098 struct ipa_sys_connect_params *ipa;
4099 uint32_t desc_fifo_sz;
4100
4101 /* The maximum number of descriptors that can be provided to a BAM at
4102 * once is one less than the total number of descriptors that the buffer
4103 * can contain.
4104 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4105 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4106 * be provided at once.
4107 * Because of above requirement, one extra descriptor will be added to
4108 * make sure hardware always has one descriptor.
4109 */
4110 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4111 + sizeof(struct sps_iovec);
4112
4113 /*setup TX pipes */
4114 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4115 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4116
4117 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4118 ipa->desc_fifo_sz = desc_fifo_sz;
4119 ipa->priv = &hdd_ipa->iface_context[i];
4120 ipa->notify = hdd_ipa_i2w_cb;
4121
4122 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4123 ipa->ipa_ep_cfg.hdr.hdr_len =
4124 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4125 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4126 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4127 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4128 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4129 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4130 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4131 } else {
4132 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4133 }
4134 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4135
4136 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4137 ipa->keep_ipa_awake = 1;
4138
4139 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4140 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304141 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004142 " ret: %d", i, ret);
4143 goto setup_sys_pipe_fail;
4144 }
4145 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4146 }
4147
4148 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4149 /*
4150 * Hard code it here, this can be extended if in case
4151 * PROD pipe is also per interface.
4152 * Right now there is no advantage of doing this.
4153 */
4154 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
4155
4156 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4157
4158 ipa->client = hdd_ipa->prod_client;
4159
4160 ipa->desc_fifo_sz = desc_fifo_sz;
4161 ipa->priv = hdd_ipa;
4162 ipa->notify = hdd_ipa_w2i_cb;
4163
4164 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4165 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4166 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4167 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4168
4169 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4170 ipa->keep_ipa_awake = 1;
4171
4172 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
4173 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304174 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004175 "Failed for RX pipe: %d", ret);
4176 goto setup_sys_pipe_fail;
4177 }
4178 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4179 }
4180
4181 return ret;
4182
4183setup_sys_pipe_fail:
4184
4185 while (--i >= 0) {
4186 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304187 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004188 sizeof(struct hdd_ipa_sys_pipe));
4189 }
4190
4191 return ret;
4192}
4193
4194/**
4195 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
4196 * @hdd_ipa: Global HDD IPA context
4197 *
4198 * Return: None
4199 */
4200static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4201{
4202 int ret = 0, i;
4203 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
4204 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
4205 ret =
4206 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
4207 conn_hdl);
4208 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304209 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004210 ret);
4211
4212 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
4213 }
4214 }
4215}
4216
4217/**
4218 * hdd_ipa_register_interface() - register IPA interface
4219 * @hdd_ipa: Global IPA context
4220 * @iface_context: Per-interface IPA context
4221 *
4222 * Return: 0 on success, negative errno on error
4223 */
4224static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
4225 struct hdd_ipa_iface_context
4226 *iface_context)
4227{
4228 struct ipa_tx_intf tx_intf;
4229 struct ipa_rx_intf rx_intf;
4230 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
4231 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
4232 char *ifname = iface_context->adapter->dev->name;
4233
4234 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
4235 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
4236
4237 int num_prop = 1;
4238 int ret = 0;
4239
4240 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
4241 num_prop++;
4242
4243 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
4244 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304245 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004246 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304247 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004248 goto register_interface_fail;
4249 }
4250
4251 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
4252 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304253 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304255 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004256 goto register_interface_fail;
4257 }
4258
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304259 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
4260 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004261
4262 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4263 ifname, HDD_IPA_IPV4_NAME_EXT);
4264 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
4265 ifname, HDD_IPA_IPV6_NAME_EXT);
4266
4267 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4268 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
4269 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4270 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4271
4272 /*
4273 * Interface ID is 3rd byte in the CLD header. Add the meta data and
4274 * mask to identify the interface in IPA hardware
4275 */
4276 rx_prop[IPA_IP_v4].attrib.meta_data =
4277 htonl(iface_context->adapter->sessionId << 16);
4278 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4279
4280 rx_intf.num_props++;
4281 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4282 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4283 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
4284 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4285 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
4286 rx_prop[IPA_IP_v4].attrib.meta_data =
4287 htonl(iface_context->adapter->sessionId << 16);
4288 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
4289
4290 rx_intf.num_props++;
4291 }
4292
4293 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
4294 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4295 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4296 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
4297 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
4298 IPA_RESOURCE_NAME_MAX);
4299 tx_intf.num_props++;
4300
4301 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4302 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
4303 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
4304 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
4305 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
4306 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
4307 IPA_RESOURCE_NAME_MAX);
4308 tx_intf.num_props++;
4309 }
4310
4311 tx_intf.prop = tx_prop;
4312 rx_intf.prop = rx_prop;
4313
4314 /* Call the ipa api to register interface */
4315 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
4316
4317register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304318 qdf_mem_free(tx_prop);
4319 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004320 return ret;
4321}
4322
4323/**
4324 * hdd_remove_ipa_header() - Remove a specific header from IPA
4325 * @name: Name of the header to be removed
4326 *
4327 * Return: None
4328 */
4329static void hdd_ipa_remove_header(char *name)
4330{
4331 struct ipa_ioc_get_hdr hdrlookup;
4332 int ret = 0, len;
4333 struct ipa_ioc_del_hdr *ipa_hdr;
4334
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304335 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004336 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
4337 ret = ipa_get_hdr(&hdrlookup);
4338 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304339 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 name, ret);
4341 return;
4342 }
4343
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304344 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004345 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304346 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004347 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304348 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004349 return;
4350 }
4351 ipa_hdr->num_hdls = 1;
4352 ipa_hdr->commit = 0;
4353 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
4354 ipa_hdr->hdl[0].status = -1;
4355 ret = ipa_del_hdr(ipa_hdr);
4356 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304357 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004358 ret);
4359
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304360 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004361}
4362
4363/**
Yun Parkb187d542016-11-14 18:10:04 -08004364 * wlan_ipa_add_hdr() - Add IPA Tx header
4365 * @ipa_hdr: pointer to IPA header addition parameters
4366 *
4367 * Call IPA API to add IPA Tx header descriptor
4368 * and dump Tx header struct
4369 *
4370 * Return: 0 for success, non-zero for failure
4371 */
4372static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr)
4373{
4374 int ret;
4375
4376 hdd_info("==== IPA Tx Header ====\n"
4377 "name: %s\n"
4378 "hdr_len: %d\n"
4379 "type: %d\n"
4380 "is_partial: %d\n"
4381 "hdr_hdl: 0x%x\n"
4382 "status: %d\n"
4383 "is_eth2_ofst_valid: %d\n"
4384 "eth2_ofst: %d\n",
4385 ipa_hdr->hdr[0].name,
4386 ipa_hdr->hdr[0].hdr_len,
4387 ipa_hdr->hdr[0].type,
4388 ipa_hdr->hdr[0].is_partial,
4389 ipa_hdr->hdr[0].hdr_hdl,
4390 ipa_hdr->hdr[0].status,
4391 ipa_hdr->hdr[0].is_eth2_ofst_valid,
4392 ipa_hdr->hdr[0].eth2_ofst);
4393
4394 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:",
4395 ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4396
4397 ret = ipa_add_hdr(ipa_hdr);
4398 return ret;
4399}
4400
4401/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004402 * hdd_ipa_add_header_info() - Add IPA header for a given interface
4403 * @hdd_ipa: Global HDD IPA context
4404 * @iface_context: Interface-specific HDD IPA context
4405 * @mac_addr: Interface MAC address
4406 *
4407 * Return: 0 on success, negativer errno value on error
4408 */
4409static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
4410 struct hdd_ipa_iface_context *iface_context,
4411 uint8_t *mac_addr)
4412{
4413 hdd_adapter_t *adapter = iface_context->adapter;
4414 char *ifname;
4415 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
4416 int ret = -EINVAL;
4417 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
4418 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
4419
4420 ifname = adapter->dev->name;
4421
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304422 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423 ifname, mac_addr);
4424
4425 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304426 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 + sizeof(struct ipa_hdr_add));
4428 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304429 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430 "%s: ipa_hdr allocation failed", ifname);
4431 ret = -ENOMEM;
4432 goto end;
4433 }
4434
4435 ipa_hdr->commit = 0;
4436 ipa_hdr->num_hdrs = 1;
4437
4438 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4439 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4440 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
4441 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4442 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304443 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004444 "ifname=%s, vdev_id=%d",
4445 ifname, uc_tx_hdr->ipa_hd.vdev_id);
4446 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4447 ifname, HDD_IPA_IPV4_NAME_EXT);
4448 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
4449 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
4450 ipa_hdr->hdr[0].is_partial = 1;
4451 ipa_hdr->hdr[0].hdr_hdl = 0;
4452 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4453 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4454
Yun Parkb187d542016-11-14 18:10:04 -08004455 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004456 } else {
4457 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4458
4459 /* Set the Source MAC */
4460 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
4461 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
4462
4463 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4464 ifname, HDD_IPA_IPV4_NAME_EXT);
4465 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4466 ipa_hdr->hdr[0].is_partial = 1;
4467 ipa_hdr->hdr[0].hdr_hdl = 0;
4468 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
4469 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4470
4471 /* Set the type to IPV4 in the header */
4472 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
4473
4474 ret = ipa_add_hdr(ipa_hdr);
4475 }
4476 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304477 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004478 ifname, ret);
4479 goto end;
4480 }
4481
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304482 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004483 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4484
4485 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4486 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4487 ifname, HDD_IPA_IPV6_NAME_EXT);
4488
4489 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4490 uc_tx_hdr =
4491 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
4492 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004493 ret = wlan_ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494 } else {
4495 /* Set the type to IPV6 in the header */
4496 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
4497 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
Yun Parkb187d542016-11-14 18:10:04 -08004498 ret = ipa_add_hdr(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004499 }
4500
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004501 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304502 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004503 "%s: IPv6 add hdr failed: %d", ifname, ret);
4504 goto clean_ipv4_hdr;
4505 }
4506
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304507 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004508 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
4509 }
4510
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304511 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512
4513 return ret;
4514
4515clean_ipv4_hdr:
4516 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
4517 ifname, HDD_IPA_IPV4_NAME_EXT);
4518 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
4519end:
4520 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304521 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004522
4523 return ret;
4524}
4525
4526/**
4527 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
4528 * @adapter: Adapter upon which IPA was previously configured
4529 *
4530 * Return: None
4531 */
4532static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
4533{
4534 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4535 int ret;
4536 char name_ipa[IPA_RESOURCE_NAME_MAX];
4537
4538 /* Remove the headers */
4539 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4540 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
4541 hdd_ipa_remove_header(name_ipa);
4542
4543 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
4544 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
4545 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
4546 hdd_ipa_remove_header(name_ipa);
4547 }
4548 /* unregister the interface with IPA */
4549 ret = ipa_deregister_intf(adapter->dev->name);
4550 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304551 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004552 "%s: ipa_deregister_intf fail: %d",
4553 adapter->dev->name, ret);
4554}
4555
4556/**
4557 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
4558 * @iface_context: interface-specific IPA context
4559 *
4560 * Return: None
4561 */
4562static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
4563{
4564 if (iface_context == NULL)
4565 return;
4566
4567 hdd_ipa_clean_hdr(iface_context->adapter);
4568
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304569 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004570 iface_context->adapter->ipa_context = NULL;
4571 iface_context->adapter = NULL;
4572 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304573 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004574 iface_context->ifa_address = 0;
4575 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304576 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004577 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05304578 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004579 }
4580 iface_context->hdd_ipa->num_iface--;
4581}
4582
4583/**
4584 * hdd_ipa_setup_iface() - Setup IPA on a given interface
4585 * @hdd_ipa: HDD IPA global context
4586 * @adapter: Interface upon which IPA is being setup
4587 * @sta_id: Station ID of the API instance
4588 *
4589 * Return: 0 on success, negative errno value on error
4590 */
4591static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
4592 hdd_adapter_t *adapter, uint8_t sta_id)
4593{
4594 struct hdd_ipa_iface_context *iface_context = NULL;
4595 void *tl_context = NULL;
4596 int i, ret = 0;
4597
4598 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
4599 * channel change indication. Since these indications are sent by lower
4600 * layer as SAP updates and IPA doesn't have to do anything for these
4601 * updates so ignoring!
4602 */
Krunal Sonibe766b02016-03-10 13:00:44 -08004603 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004604 return 0;
4605
4606 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4607 if (hdd_ipa->iface_context[i].adapter == NULL) {
4608 iface_context = &(hdd_ipa->iface_context[i]);
4609 break;
4610 }
4611 }
4612
4613 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304614 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615 "All the IPA interfaces are in use");
4616 ret = -ENOMEM;
4617 goto end;
4618 }
4619
4620 adapter->ipa_context = iface_context;
4621 iface_context->adapter = adapter;
4622 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08004623 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Leo Changfdb45c32016-10-28 11:09:23 -07004624 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004625 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304626 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004627 "Not able to get TL context sta_id: %d", sta_id);
4628 ret = -EINVAL;
4629 goto end;
4630 }
4631
4632 iface_context->tl_context = tl_context;
4633
4634 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
4635 adapter->dev->dev_addr);
4636
4637 if (ret)
4638 goto end;
4639
4640 /* Configure the TX and RX pipes filter rules */
4641 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
4642 if (ret)
4643 goto cleanup_header;
4644
4645 hdd_ipa->num_iface++;
4646 return ret;
4647
4648cleanup_header:
4649
4650 hdd_ipa_clean_hdr(adapter);
4651end:
4652 if (iface_context)
4653 hdd_ipa_cleanup_iface(iface_context);
4654 return ret;
4655}
4656
Yun Parka27049a2016-10-11 12:30:49 -07004657#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004659 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004660 * @mcc_mode: 0=MCC/1=SCC
4661 *
4662 * Return: 0 on success, negative errno value on error
4663 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004664static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004665{
4666 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304667 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004668 hdd_adapter_t *pAdapter;
4669 struct ipa_msg_meta meta;
4670 struct ipa_wlan_msg *msg;
4671 int ret;
4672
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004673 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004674 return -EINVAL;
4675
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004676 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
4677 return -EINVAL;
4678
4679 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004680 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004681 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304682 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004683 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08004684 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004685 pAdapter->device_mode == QDF_SAP_MODE) {
4686 hdd_info("MCC->SCC: Flush TxRx queue(d_mode=%d)",
4687 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004688 hdd_deinit_tx_rx(pAdapter);
4689 }
4690 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004691 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004692 adapter_node = next;
4693 }
4694 }
4695
4696 /* Send SCC/MCC Switching event to IPA */
4697 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304698 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004699 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004700 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004701 return -ENOMEM;
4702 }
4703
4704 meta.msg_type = mcc_mode ?
4705 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004706 hdd_info("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707
4708 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4709
4710 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004711 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004712 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304713 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004714 }
4715
4716 return ret;
4717}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004718
4719/**
4720 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4721 * @mcc_mode: 0=MCC/1=SCC
4722 *
4723 * Return: 0 on success, negative errno value on error
4724 */
4725int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
4726{
4727 int ret;
4728
4729 cds_ssr_protect(__func__);
4730 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4731 cds_ssr_unprotect(__func__);
4732
4733 return ret;
4734}
Yun Parka27049a2016-10-11 12:30:49 -07004735#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004736
4737/**
4738 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4739 * @event: IPA WLAN event to be converted to a string
4740 *
4741 * Return: ASCII string representing the IPA WLAN event
4742 */
4743static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4744{
4745 switch (event) {
4746 case WLAN_CLIENT_CONNECT:
4747 return "WLAN_CLIENT_CONNECT";
4748 case WLAN_CLIENT_DISCONNECT:
4749 return "WLAN_CLIENT_DISCONNECT";
4750 case WLAN_CLIENT_POWER_SAVE_MODE:
4751 return "WLAN_CLIENT_POWER_SAVE_MODE";
4752 case WLAN_CLIENT_NORMAL_MODE:
4753 return "WLAN_CLIENT_NORMAL_MODE";
4754 case SW_ROUTING_ENABLE:
4755 return "SW_ROUTING_ENABLE";
4756 case SW_ROUTING_DISABLE:
4757 return "SW_ROUTING_DISABLE";
4758 case WLAN_AP_CONNECT:
4759 return "WLAN_AP_CONNECT";
4760 case WLAN_AP_DISCONNECT:
4761 return "WLAN_AP_DISCONNECT";
4762 case WLAN_STA_CONNECT:
4763 return "WLAN_STA_CONNECT";
4764 case WLAN_STA_DISCONNECT:
4765 return "WLAN_STA_DISCONNECT";
4766 case WLAN_CLIENT_CONNECT_EX:
4767 return "WLAN_CLIENT_CONNECT_EX";
4768
4769 case IPA_WLAN_EVENT_MAX:
4770 default:
4771 return "UNKNOWN";
4772 }
4773}
4774
4775/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004776 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4777 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4778 *
4779 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4780 */
4781static enum ipa_wlan_event
4782hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4783{
4784 enum ipa_wlan_event ipa_event;
4785
4786 switch (hdd_ipa_event_type) {
4787 case HDD_IPA_CLIENT_CONNECT:
4788 ipa_event = WLAN_CLIENT_CONNECT;
4789 break;
4790 case HDD_IPA_CLIENT_DISCONNECT:
4791 ipa_event = WLAN_CLIENT_DISCONNECT;
4792 break;
4793 case HDD_IPA_AP_CONNECT:
4794 ipa_event = WLAN_AP_CONNECT;
4795 break;
4796 case HDD_IPA_AP_DISCONNECT:
4797 ipa_event = WLAN_AP_DISCONNECT;
4798 break;
4799 case HDD_IPA_STA_CONNECT:
4800 ipa_event = WLAN_STA_CONNECT;
4801 break;
4802 case HDD_IPA_STA_DISCONNECT:
4803 ipa_event = WLAN_STA_DISCONNECT;
4804 break;
4805 case HDD_IPA_CLIENT_CONNECT_EX:
4806 ipa_event = WLAN_CLIENT_CONNECT_EX;
4807 break;
4808 case HDD_IPA_WLAN_EVENT_MAX:
4809 default:
4810 ipa_event = IPA_WLAN_EVENT_MAX;
4811 break;
4812 }
4813 return ipa_event;
4814
4815}
4816
4817/**
4818 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004819 * @adapter: adapter upon which the event was received
4820 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004821 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004822 * @mac_address: MAC address associated with the event
4823 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004824 * This function is meant to be called from within wlan_hdd_ipa.c
4825 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004826 * Return: 0 on success, negative errno value on error
4827 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07004828static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004829 enum ipa_wlan_event type, uint8_t *mac_addr)
4830{
4831 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4832 struct ipa_msg_meta meta;
4833 struct ipa_wlan_msg *msg;
4834 struct ipa_wlan_msg_ex *msg_ex = NULL;
4835 int ret;
4836
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304837 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004838 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
4839 mac_addr, sta_id);
4840
4841 if (type >= IPA_WLAN_EVENT_MAX)
4842 return -EINVAL;
4843
4844 if (WARN_ON(is_zero_ether_addr(mac_addr)))
4845 return -EINVAL;
4846
4847 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304848 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004849 return -EINVAL;
4850 }
4851
4852 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
4853 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08004854 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004855 return 0;
4856 }
4857
4858 /*
4859 * During IPA UC resource loading/unloading new events can be issued.
4860 * Store the events separately and handle them later.
4861 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004862 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4863 if (hdd_ipa->resource_loading) {
4864 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004865 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08004866
Yun Park7c4f31b2016-11-30 10:09:21 -08004867 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA resource %s inprogress",
4868 hdd_ipa->resource_loading ? "load":"unload");
4869
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004870 hdd_err("IPA resource %s inprogress",
4871 hdd_ipa->resource_loading ? "load":"unload");
Yun Parkf19e07d2015-11-20 11:34:27 -08004872
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004873 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004874
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004875 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4876 if (pending_event_count >= HDD_IPA_MAX_PENDING_EVENT_COUNT) {
4877 hdd_notice("Reached max pending event count");
4878 qdf_list_remove_front(&hdd_ipa->pending_event,
4879 (qdf_list_node_t **)&pending_event);
4880 } else {
4881 pending_event =
4882 (struct ipa_uc_pending_event *)qdf_mem_malloc(
4883 sizeof(struct ipa_uc_pending_event));
4884 }
4885
4886 if (!pending_event) {
Yun Park7c4f31b2016-11-30 10:09:21 -08004887 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4888 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004889 qdf_mutex_release(&hdd_ipa->event_lock);
4890 return -ENOMEM;
4891 }
4892
4893 pending_event->adapter = adapter;
4894 pending_event->sta_id = sta_id;
4895 pending_event->type = type;
4896 qdf_mem_copy(pending_event->mac_addr,
4897 mac_addr,
4898 QDF_MAC_ADDR_SIZE);
4899 qdf_list_insert_back(&hdd_ipa->pending_event,
4900 &pending_event->node);
4901
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304902 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004903 return 0;
4904 } else if (hdd_ipa->resource_unloading) {
4905 hdd_err("%s: IPA resource unload inprogress", __func__);
4906 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004907 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004908 }
4909
4910 hdd_ipa->stats.event[type]++;
4911
Leo Chang3bc8fed2015-11-13 10:59:47 -08004912 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004913 switch (type) {
4914 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004915 qdf_mutex_acquire(&hdd_ipa->event_lock);
4916
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004917 /* STA already connected and without disconnect, connect again
4918 * This is Roaming scenario
4919 */
4920 if (hdd_ipa->sta_connected)
4921 hdd_ipa_cleanup_iface(adapter->ipa_context);
4922
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004923 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4924 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304925 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004926 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004927 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004928
Yun Park8f289c82016-10-18 16:38:21 -07004929 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4930 (hdd_ipa->sap_num_connected_sta > 0) &&
4931 !hdd_ipa->sta_connected) {
4932 qdf_mutex_release(&hdd_ipa->event_lock);
4933 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004934 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004935 qdf_mutex_acquire(&hdd_ipa->event_lock);
4936 }
4937
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004938 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004939 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004940 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004941
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004942 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07004943
4944 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004945 break;
4946
4947 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004948 qdf_mutex_acquire(&hdd_ipa->event_lock);
4949
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004950 /* For DFS channel we get two start_bss event (before and after
4951 * CAC). Also when ACS range includes both DFS and non DFS
4952 * channels, we could possibly change channel many times due to
4953 * RADAR detection and chosen channel may not be a DFS channels.
4954 * So dont return error here. Just discard the event.
4955 */
Yun Park8f289c82016-10-18 16:38:21 -07004956 if (adapter->ipa_context) {
4957 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004958 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07004959 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004960
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004961 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4962 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004963 hdd_err("%s: Evt: %d, Interface setup failed",
4964 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304965 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004966 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004967 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004968
Yun Park8f289c82016-10-18 16:38:21 -07004969 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4970 qdf_mutex_release(&hdd_ipa->event_lock);
4971 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004972 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004973 qdf_mutex_acquire(&hdd_ipa->event_lock);
4974 }
4975
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004976 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004977 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004978 (adapter->ipa_context))->iface_id;
4979
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304980 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004981 break;
4982
4983 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304984 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004985
4986 if (!hdd_ipa->sta_connected) {
Yun Parkb187d542016-11-14 18:10:04 -08004987 hdd_err("%s: Evt: %d, STA already disconnected",
4988 msg_ex->name, meta.msg_type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304989 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004990 return -EINVAL;
4991 }
Yun Parka37592b2016-06-11 17:10:28 -07004992
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004993 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07004994
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004995 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Parkb187d542016-11-14 18:10:04 -08004996 hdd_notice("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004997 msg_ex->name);
4998 } else {
4999 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07005000 if (!hdd_ipa->num_iface &&
5001 (HDD_IPA_UC_NUM_WDI_PIPE ==
5002 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005003 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005004 }
5005
Yun Park74127cf2016-09-18 11:22:41 -07005006 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5007 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005008 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005009 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005010 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005011 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005012 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5013 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005014 }
5015
Yun Park8f289c82016-10-18 16:38:21 -07005016 hdd_ipa_cleanup_iface(adapter->ipa_context);
5017
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305018 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005019 break;
5020
5021 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005022 qdf_mutex_acquire(&hdd_ipa->event_lock);
5023
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005024 if (!adapter->ipa_context) {
Yun Parkb187d542016-11-14 18:10:04 -08005025 hdd_err("%s: Evt: %d, SAP already disconnected",
5026 msg_ex->name, meta.msg_type);
Yun Park8f289c82016-10-18 16:38:21 -07005027 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005028 return -EINVAL;
5029 }
5030
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005031 if ((!hdd_ipa->num_iface) &&
5032 (HDD_IPA_UC_NUM_WDI_PIPE ==
5033 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005034 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005035 /*
5036 * We disable WDI pipes directly here since
5037 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5038 * processed when unloading WLAN driver is in
5039 * progress
5040 */
5041 hdd_ipa_uc_disable_pipes(hdd_ipa);
5042 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305043 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005044 "NO INTF left but still pipe clean up");
5045 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5046 }
5047 }
5048
5049 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005050 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005051 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005052 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005053 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005054 hdd_ipa->vdev_to_iface[adapter->sessionId] =
5055 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005056 }
Yun Parka37592b2016-06-11 17:10:28 -07005057
Yun Park8f289c82016-10-18 16:38:21 -07005058 hdd_ipa_cleanup_iface(adapter->ipa_context);
5059
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305060 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005061 break;
5062
5063 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005064 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305065 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005066 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305067 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005068 return 0;
5069 }
5070
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305071 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005072 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5073 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005074 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305075 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005076 "%s: STA ID %d found, not valid",
5077 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005078 return 0;
5079 }
Yun Park312f71a2015-12-08 10:22:42 -08005080
5081 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005082 if (hdd_ipa->sap_num_connected_sta == 0 &&
5083 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005084 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005085 hdd_ipa->sta_connected) {
5086 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005087 hdd_ipa_uc_offload_enable_disable(
5088 hdd_get_adapter(hdd_ipa->hdd_ctx,
5089 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005090 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005091 qdf_mutex_acquire(&hdd_ipa->event_lock);
5092 }
Yun Parka37592b2016-06-11 17:10:28 -07005093
Yun Park312f71a2015-12-08 10:22:42 -08005094 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5095 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305096 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08005097 "%s: handle 1st con ret %d",
5098 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005099
5100 if (hdd_ipa_uc_sta_is_enabled(
5101 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005102 hdd_ipa->sta_connected) {
5103 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005104 hdd_ipa_uc_offload_enable_disable(
5105 hdd_get_adapter(
5106 hdd_ipa->hdd_ctx,
5107 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005108 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005109 } else {
5110 qdf_mutex_release(&hdd_ipa->event_lock);
5111 }
Yun Parka37592b2016-06-11 17:10:28 -07005112
Yun Park312f71a2015-12-08 10:22:42 -08005113 return ret;
5114 }
5115 }
5116
5117 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005118
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305119 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005120
5121 meta.msg_type = type;
5122 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
5123 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305124 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005125
5126 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305127 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005128 "msg_ex allocation failed");
5129 return -ENOMEM;
5130 }
5131 strlcpy(msg_ex->name, adapter->dev->name,
5132 IPA_RESOURCE_NAME_MAX);
5133 msg_ex->num_of_attribs = 1;
5134 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5135 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5136 msg_ex->attribs[0].offset =
5137 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5138 } else {
5139 msg_ex->attribs[0].offset =
5140 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5141 }
5142 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5143 IPA_MAC_ADDR_SIZE);
5144
5145 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5146
5147 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305148 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305149 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305150 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005151 return ret;
5152 }
5153 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005154 return ret;
5155
5156 case WLAN_CLIENT_DISCONNECT:
5157 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305158 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005159 "%s: IPA UC OFFLOAD NOT ENABLED",
5160 msg_ex->name);
5161 return 0;
5162 }
5163
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305164 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005165 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305166 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005167 "%s: STA ID %d NOT found, not valid",
5168 msg_ex->name, sta_id);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305169 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005170 return 0;
5171 }
5172 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005173
Yun Park9b5030f2016-11-08 12:02:37 -08005174 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005175 if (!hdd_ipa->sap_num_connected_sta &&
5176 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005177 if ((false == hdd_ipa->resource_unloading)
5178 && (HDD_IPA_UC_NUM_WDI_PIPE ==
5179 hdd_ipa->activated_fw_pipe)) {
5180 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5181 }
5182
Yun Park8f289c82016-10-18 16:38:21 -07005183 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005184
5185 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5186 hdd_ipa->sta_connected)
5187 hdd_ipa_uc_offload_enable_disable(
5188 hdd_get_adapter(hdd_ipa->hdd_ctx,
5189 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005190 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005191 } else {
5192 qdf_mutex_release(&hdd_ipa->event_lock);
5193 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005194 break;
5195
5196 default:
5197 return 0;
5198 }
5199
5200 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305201 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005202 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305203 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005204 return -ENOMEM;
5205 }
5206
5207 meta.msg_type = type;
5208 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
5209 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
5210
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305211 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005212 msg->name, meta.msg_type);
5213
5214 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5215
5216 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005217 hdd_err("%s: Evt: %d fail:%d",
5218 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305219 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005220 return ret;
5221 }
5222
5223 hdd_ipa->stats.num_send_msg++;
5224
5225end:
5226 return ret;
5227}
5228
5229/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005230 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005231 * @adapter: adapter upon which the event was received
5232 * @sta_id: station id for the event
5233 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5234 * @mac_address: MAC address associated with the event
5235 *
5236 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5237 *
5238 * Return: 0 on success, negative errno value on error
5239 */
5240int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
5241 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5242{
5243 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005244 int ret = 0;
5245
5246 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005247
Leo Changa202b522016-10-14 16:13:50 -07005248 /* Data path offload only support for STA and SAP mode */
5249 if ((QDF_STA_MODE == adapter->device_mode) ||
5250 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005251 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005252
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005253 cds_ssr_unprotect(__func__);
5254
5255 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005256}
5257
5258/**
5259 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5260 * @hdd_ipa: Global HDD IPA context
5261 *
5262 * Return: None
5263 */
5264static void
5265hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5266{
5267 unsigned int pending_event_count;
5268 struct ipa_uc_pending_event *pending_event = NULL;
5269
5270 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
5271 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
5272 "%s, Pending Event Count %d", __func__, pending_event_count);
5273 if (!pending_event_count) {
5274 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
5275 "%s, No Pending Event", __func__);
5276 return;
5277 }
5278
5279 qdf_list_remove_front(&hdd_ipa->pending_event,
5280 (qdf_list_node_t **)&pending_event);
5281 while (pending_event != NULL) {
5282 __hdd_ipa_wlan_evt(pending_event->adapter,
5283 pending_event->type,
5284 pending_event->sta_id,
5285 pending_event->mac_addr);
5286 qdf_mem_free(pending_event);
5287 pending_event = NULL;
5288 qdf_list_remove_front(&hdd_ipa->pending_event,
5289 (qdf_list_node_t **)&pending_event);
5290 }
5291}
5292
5293/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005294 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5295 * @state: IPA RM state value
5296 *
5297 * Return: ASCII string representing the IPA RM state
5298 */
5299static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5300{
5301 switch (state) {
5302 case HDD_IPA_RM_RELEASED:
5303 return "RELEASED";
5304 case HDD_IPA_RM_GRANT_PENDING:
5305 return "GRANT_PENDING";
5306 case HDD_IPA_RM_GRANTED:
5307 return "GRANTED";
5308 }
5309
5310 return "UNKNOWN";
5311}
5312
5313/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005314 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005315 * @hdd_ctx: HDD global context
5316 *
5317 * Allocate hdd_ipa resources, ipa pipe resource and register
5318 * wlan interface with IPA module.
5319 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305320 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005321 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005322static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005323{
5324 struct hdd_ipa_priv *hdd_ipa = NULL;
5325 int ret, i;
5326 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park7f171ab2016-07-29 15:44:22 -07005327 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005328
5329 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305330 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005331
Yun Park7f171ab2016-07-29 15:44:22 -07005332 if (!pdev) {
5333 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5334 goto fail_return;
5335 }
5336
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305337 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005338 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305339 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005340 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005341 }
5342
5343 hdd_ctx->hdd_ipa = hdd_ipa;
5344 ghdd_ipa = hdd_ipa;
5345 hdd_ipa->hdd_ctx = hdd_ctx;
5346 hdd_ipa->num_iface = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07005347 cdp_ipa_get_resource(cds_get_context(QDF_MODULE_ID_SOC),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08005348 (struct cdp_pdev *)cds_get_context(QDF_MODULE_ID_TXRX),
5349 &hdd_ipa->ipa_resource);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08005350 if ((0 == hdd_ipa->ipa_resource.ce_sr_base_paddr) ||
5351 (0 == hdd_ipa->ipa_resource.tx_comp_ring_base_paddr) ||
5352 (0 == hdd_ipa->ipa_resource.rx_rdy_ring_base_paddr) ||
5353 (0 == hdd_ipa->ipa_resource.rx2_rdy_ring_base_paddr)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305354 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Leo Chang3bc8fed2015-11-13 10:59:47 -08005355 "IPA UC resource alloc fail");
5356 goto fail_get_resource;
5357 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005358
5359 /* Create the interface context */
5360 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5361 iface_context = &hdd_ipa->iface_context[i];
5362 iface_context->hdd_ipa = hdd_ipa;
5363 iface_context->cons_client =
5364 hdd_ipa_adapter_2_client[i].cons_client;
5365 iface_context->prod_client =
5366 hdd_ipa_adapter_2_client[i].prod_client;
5367 iface_context->iface_id = i;
5368 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305369 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005370 }
5371 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005372 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5373 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005374 }
5375
Leo Chang69c39692016-10-12 20:11:12 -07005376 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305377 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305378 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005379
5380 ret = hdd_ipa_setup_rm(hdd_ipa);
5381 if (ret)
5382 goto fail_setup_rm;
5383
5384 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5385 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305386 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005387 hdd_ipa->sap_num_connected_sta = 0;
5388 hdd_ipa->ipa_tx_packets_diff = 0;
5389 hdd_ipa->ipa_rx_packets_diff = 0;
5390 hdd_ipa->ipa_p_tx_packets = 0;
5391 hdd_ipa->ipa_p_rx_packets = 0;
5392 hdd_ipa->resource_loading = false;
5393 hdd_ipa->resource_unloading = false;
5394 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005395 hdd_ipa->ipa_pipes_down = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005396 /* Setup IPA sys_pipe for MCC */
5397 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5398 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5399 if (ret)
5400 goto fail_create_sys_pipe;
5401 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005402 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5403 goto fail_create_sys_pipe;
5404
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005405 hdd_ipa_uc_ol_init(hdd_ctx);
5406 } else {
5407 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5408 if (ret)
5409 goto fail_create_sys_pipe;
5410 }
5411
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305412 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005413
5414fail_create_sys_pipe:
5415 hdd_ipa_destroy_rm_resource(hdd_ipa);
5416fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305417 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005418fail_get_resource:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305419 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005420 hdd_ctx->hdd_ipa = NULL;
5421 ghdd_ipa = NULL;
5422fail_return:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305423 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005424}
5425
5426/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005427 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5428 * @hdd_ctx: HDD global context
5429 *
5430 * Allocate hdd_ipa resources, ipa pipe resource and register
5431 * wlan interface with IPA module.
5432 *
5433 * Return: QDF_STATUS enumeration
5434 */
5435QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
5436{
5437 QDF_STATUS ret;
5438
5439 cds_ssr_protect(__func__);
5440 ret = __hdd_ipa_init(hdd_ctx);
5441 cds_ssr_unprotect(__func__);
5442
5443 return ret;
5444}
5445
Arun Khandavallicc544b32017-01-30 19:52:16 +05305446
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005447/**
Yun Parkf19e07d2015-11-20 11:34:27 -08005448 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
5449 * @hdd_ipa: pointer to HDD IPA struct
5450 *
5451 * Return: none
5452 */
Jeff Johnsond7720632016-10-05 16:04:32 -07005453static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08005454{
5455 struct ipa_uc_pending_event *pending_event = NULL;
5456
Anurag Chouhanffb21542016-02-17 14:33:03 +05305457 while (qdf_list_remove_front(&hdd_ipa->pending_event,
5458 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305459 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005460 }
5461
Anurag Chouhanffb21542016-02-17 14:33:03 +05305462 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08005463}
5464
5465/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005466 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005467 * @hdd_ctx: HDD global context
5468 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305469 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005470 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005471static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005472{
5473 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
5474 int i;
5475 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05305476 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005477 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
5478
5479 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305480 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005481
5482 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
5483 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
5484 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5485 }
5486
5487 /* Teardown IPA sys_pipe for MCC */
5488 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
5489 hdd_ipa_teardown_sys_pipe(hdd_ipa);
5490
5491 hdd_ipa_destroy_rm_resource(hdd_ipa);
5492
5493#ifdef WLAN_OPEN_SOURCE
5494 cancel_work_sync(&hdd_ipa->pm_work);
5495#endif
5496
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305497 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005498
Nirav Shahcbc6d722016-03-01 16:24:53 +05305499 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
5500 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305501 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005502
5503 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
5504 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
5505
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305506 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005507 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305508 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005509
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305510 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005511
5512 /* destory the interface lock */
5513 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5514 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305515 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005516 }
5517
5518 /* This should never hit but still make sure that there are no pending
5519 * descriptor in IPA hardware
5520 */
5521 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305522 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005523 "IPA Pending write done: %d Waiting!",
5524 hdd_ipa->pending_hw_desc_cnt);
5525
5526 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
5527 usleep_range(100, 100);
5528 }
5529
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305530 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005531 "IPA Pending write done: desc: %d %s(%d)!",
5532 hdd_ipa->pending_hw_desc_cnt,
5533 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
5534 : "leak", i);
5535 }
5536 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08005537 if (ipa_uc_dereg_rdyCB())
5538 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5539 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005540 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005541 if (true == hdd_ipa->uc_loaded) {
5542 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305543 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
5544 __func__, hdd_ipa->tx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005545 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
5546 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05305547 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
5548 __func__, hdd_ipa->rx_pipe_handle);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005549 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
5550 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305551 qdf_mutex_destroy(&hdd_ipa->event_lock);
5552 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005553 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005554
5555#ifdef WLAN_OPEN_SOURCE
5556 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5557 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
5558 hdd_ipa->uc_op_work[i].msg = NULL;
5559 }
5560#endif
5561 }
5562
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305563 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005564 hdd_ctx->hdd_ipa = NULL;
5565
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305566 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005567}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005568
5569/**
5570 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
5571 * @hdd_ctx: HDD global context
5572 *
5573 * Return: QDF_STATUS enumeration
5574 */
5575QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
5576{
5577 QDF_STATUS ret;
5578
5579 cds_ssr_protect(__func__);
5580 ret = __hdd_ipa_cleanup(hdd_ctx);
5581 cds_ssr_unprotect(__func__);
5582
5583 return ret;
5584}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005585#endif /* IPA_OFFLOAD */