blob: 2481ef5f0a6f18ae27427996af398119cf453228 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08002 * Copyright (c) 2013-2018 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 */
Yun Park84c0ceb2018-01-11 10:37:10 -080038#ifdef CONFIG_IPA_WDI_UNIFIED_API
39#include <qdf_ipa_wdi3.h>
40#else
Yun Park6c86a662017-10-05 16:09:15 -070041#include <qdf_ipa.h>
Yun Park84c0ceb2018-01-11 10:37:10 -080042#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080043#include <wlan_hdd_includes.h>
44#include <wlan_hdd_ipa.h>
45
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080046#include <linux/inetdevice.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080047#include <wlan_hdd_softap_tx_rx.h>
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +053048#include <ol_txrx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070049#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080050
51#include "cds_sched.h"
52
53#include "wma.h"
54#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080055#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080056
Dhanashri Atreb08959a2016-03-01 17:28:03 -080057#include "cdp_txrx_ipa.h"
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -080058#include "wlan_policy_mgr_api.h"
59
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080060#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080061#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
Yun Parkb4f591d2017-03-29 15:51:01 -070062
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080063#define HDD_IPA_UC_NUM_WDI_PIPE 2
64#define HDD_IPA_UC_MAX_PENDING_EVENT 33
65
66#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
67#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
68#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
69#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
70
71#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
72#define HDD_IPA_MAX_IFACE 3
73#define HDD_IPA_MAX_SYSBAM_PIPE 4
Yun Parkb4f591d2017-03-29 15:51:01 -070074
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080075#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
76#define HDD_IPA_ENABLE_MASK BIT(0)
77#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
78#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
79#define HDD_IPA_RM_ENABLE_MASK BIT(3)
80#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
81#define HDD_IPA_UC_ENABLE_MASK BIT(5)
82#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
83#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
84
Yun Park84c0ceb2018-01-11 10:37:10 -080085#define HDD_IPA_MAX_BANDWIDTH 800
86
Yun Parkf19e07d2015-11-20 11:34:27 -080087#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
88
tfyu0380a972017-07-13 18:19:37 +080089#define IPA_WLAN_RX_SOFTIRQ_THRESH 16
90
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -070091enum hdd_ipa_uc_op_code {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080092 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
93 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
94 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
95 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
96 HDD_IPA_UC_OPCODE_STATS = 4,
Yun Park637d6482016-10-05 10:51:33 -070097#ifdef FEATURE_METERING
98 HDD_IPA_UC_OPCODE_SHARING_STATS = 5,
99 HDD_IPA_UC_OPCODE_QUOTA_RSP = 6,
100 HDD_IPA_UC_OPCODE_QUOTA_IND = 7,
101#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800102 HDD_IPA_UC_OPCODE_UC_READY = 8,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800103 /* keep this last */
104 HDD_IPA_UC_OPCODE_MAX
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700105};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800106
107/**
108 * enum - Reason codes for stat query
109 *
110 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
111 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
112 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800113 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800114 */
115enum {
116 HDD_IPA_UC_STAT_REASON_NONE,
117 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Park46255682017-10-09 15:56:34 -0700118 HDD_IPA_UC_STAT_REASON_BW_CAL
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800119};
120
121/**
122 * enum hdd_ipa_rm_state - IPA resource manager state
123 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
124 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
125 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
126 */
127enum hdd_ipa_rm_state {
128 HDD_IPA_RM_RELEASED,
129 HDD_IPA_RM_GRANT_PENDING,
130 HDD_IPA_RM_GRANTED,
131};
132
133struct llc_snap_hdr {
134 uint8_t dsap;
135 uint8_t ssap;
136 uint8_t resv[4];
137 __be16 eth_type;
138} __packed;
139
Leo Chang3bc8fed2015-11-13 10:59:47 -0800140/**
141 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
142 * @eth: ether II header
143 * @llc_snap: LLC snap header
144 *
145 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800146struct hdd_ipa_tx_hdr {
147 struct ethhdr eth;
148 struct llc_snap_hdr llc_snap;
149} __packed;
150
Leo Chang3bc8fed2015-11-13 10:59:47 -0800151/**
152 * struct frag_header - fragment header type registered to IPA hardware
153 * @length: fragment length
154 * @reserved1: Reserved not used
155 * @reserved2: Reserved not used
156 *
157 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800158struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800159 uint16_t length;
160 uint32_t reserved1;
161 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800162} __packed;
163
Leo Chang3bc8fed2015-11-13 10:59:47 -0800164/**
165 * struct ipa_header - ipa header type registered to IPA hardware
166 * @vdev_id: vdev id
167 * @reserved: Reserved not used
168 *
169 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800170struct ipa_header {
171 uint32_t
172 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
173 reserved:24;
174} __packed;
175
Leo Chang3bc8fed2015-11-13 10:59:47 -0800176/**
177 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
178 * @frag_hd: fragment header
179 * @ipa_hd: ipa header
180 * @eth: ether II header
181 *
182 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800183struct hdd_ipa_uc_tx_hdr {
184 struct frag_header frag_hd;
185 struct ipa_header ipa_hd;
186 struct ethhdr eth;
187} __packed;
188
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800189/**
190 * struct hdd_ipa_cld_hdr - IPA CLD Header
191 * @reserved: reserved fields
192 * @iface_id: interface ID
193 * @sta_id: Station ID
194 *
195 * Packed 32-bit structure
196 * +----------+----------+--------------+--------+
197 * | Reserved | QCMAP ID | interface id | STA ID |
198 * +----------+----------+--------------+--------+
199 */
200struct hdd_ipa_cld_hdr {
201 uint8_t reserved[2];
202 uint8_t iface_id;
203 uint8_t sta_id;
204} __packed;
205
206struct hdd_ipa_rx_hdr {
207 struct hdd_ipa_cld_hdr cld_hdr;
208 struct ethhdr eth;
209} __packed;
210
211struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700212 bool exception;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700213 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800214 struct hdd_ipa_iface_context *iface_context;
Yun Park6c86a662017-10-05 16:09:15 -0700215 qdf_ipa_rx_data_t *ipa_tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216};
217
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800218struct hdd_ipa_sys_pipe {
219 uint32_t conn_hdl;
220 uint8_t conn_hdl_valid;
Yun Park6c86a662017-10-05 16:09:15 -0700221 qdf_ipa_sys_connect_params_t ipa_sys_params;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800222};
223
224struct hdd_ipa_iface_stats {
225 uint64_t num_tx;
226 uint64_t num_tx_drop;
227 uint64_t num_tx_err;
228 uint64_t num_tx_cac_drop;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800229 uint64_t num_rx_ipa_excep;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800230};
231
232struct hdd_ipa_priv;
233
234struct hdd_ipa_iface_context {
235 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700236 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800237 void *tl_context;
238
Yun Park6c86a662017-10-05 16:09:15 -0700239 qdf_ipa_client_type_t cons_client;
240 qdf_ipa_client_type_t prod_client;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800241
242 uint8_t iface_id; /* This iface ID */
243 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530244 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800245 uint32_t ifa_address;
246 struct hdd_ipa_iface_stats stats;
247};
248
249struct hdd_ipa_stats {
250 uint32_t event[IPA_WLAN_EVENT_MAX];
251 uint64_t num_send_msg;
252 uint64_t num_free_msg;
253
254 uint64_t num_rm_grant;
255 uint64_t num_rm_release;
256 uint64_t num_rm_grant_imm;
257 uint64_t num_cons_perf_req;
258 uint64_t num_prod_perf_req;
259
260 uint64_t num_rx_drop;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800261
Yun Park52b2b992016-09-22 15:49:51 -0700262 uint64_t num_tx_desc_q_cnt;
263 uint64_t num_tx_desc_error;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800264 uint64_t num_tx_comp_cnt;
265 uint64_t num_tx_queued;
266 uint64_t num_tx_dequeued;
267 uint64_t num_max_pm_queue;
268
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800269 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800270 uint64_t num_tx_fwd_ok;
271 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800272};
273
274struct ipa_uc_stas_map {
275 bool is_reserved;
276 uint8_t sta_id;
277};
278struct op_msg_type {
279 uint8_t msg_t;
280 uint8_t rsvd;
281 uint16_t op_code;
282 uint16_t len;
283 uint16_t rsvd_snd;
284};
285
286struct ipa_uc_fw_stats {
287 uint32_t tx_comp_ring_base;
288 uint32_t tx_comp_ring_size;
289 uint32_t tx_comp_ring_dbell_addr;
290 uint32_t tx_comp_ring_dbell_ind_val;
291 uint32_t tx_comp_ring_dbell_cached_val;
292 uint32_t tx_pkts_enqueued;
293 uint32_t tx_pkts_completed;
294 uint32_t tx_is_suspend;
295 uint32_t tx_reserved;
296 uint32_t rx_ind_ring_base;
297 uint32_t rx_ind_ring_size;
298 uint32_t rx_ind_ring_dbell_addr;
299 uint32_t rx_ind_ring_dbell_ind_val;
300 uint32_t rx_ind_ring_dbell_ind_cached_val;
301 uint32_t rx_ind_ring_rdidx_addr;
302 uint32_t rx_ind_ring_rd_idx_cached_val;
303 uint32_t rx_refill_idx;
304 uint32_t rx_num_pkts_indicated;
305 uint32_t rx_buf_refilled;
306 uint32_t rx_num_ind_drop_no_space;
307 uint32_t rx_num_ind_drop_no_buf;
308 uint32_t rx_is_suspend;
309 uint32_t rx_reserved;
310};
311
312struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530313 qdf_list_node_t node;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700314 struct hdd_adapter *adapter;
Yun Park6c86a662017-10-05 16:09:15 -0700315 qdf_ipa_wlan_event_t type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800316 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530317 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Yun Parka4bb37c2017-12-08 16:14:22 -0800318 bool is_loading;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800319};
320
321/**
322 * struct uc_rm_work_struct
323 * @work: uC RM work
324 * @event: IPA RM event
325 */
326struct uc_rm_work_struct {
327 struct work_struct work;
Yun Park6c86a662017-10-05 16:09:15 -0700328 qdf_ipa_rm_event_t event;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800329};
330
331/**
332 * struct uc_op_work_struct
333 * @work: uC OP work
334 * @msg: OP message
335 */
336struct uc_op_work_struct {
337 struct work_struct work;
338 struct op_msg_type *msg;
339};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800340
341/**
342 * struct uc_rt_debug_info
343 * @time: system time
344 * @ipa_excep_count: IPA exception packet count
345 * @rx_drop_count: IPA Rx drop packet count
346 * @net_sent_count: IPA Rx packet sent to network stack count
347 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800348 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800349 * @tx_fwd_count: IPA Tx forward packet count
350 * @rx_destructor_call: IPA Rx packet destructor count
351 */
352struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530353 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800354 uint64_t ipa_excep_count;
355 uint64_t rx_drop_count;
356 uint64_t net_sent_count;
357 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800358 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800359 uint64_t tx_fwd_count;
360 uint64_t rx_destructor_call;
361};
362
Yun Park637d6482016-10-05 10:51:33 -0700363#ifdef FEATURE_METERING
364struct ipa_uc_sharing_stats {
365 uint64_t ipv4_rx_packets;
366 uint64_t ipv4_rx_bytes;
367 uint64_t ipv6_rx_packets;
368 uint64_t ipv6_rx_bytes;
369 uint64_t ipv4_tx_packets;
370 uint64_t ipv4_tx_bytes;
371 uint64_t ipv6_tx_packets;
372 uint64_t ipv6_tx_bytes;
373};
374
375struct ipa_uc_quota_rsp {
376 uint8_t success;
377 uint8_t reserved[3];
378 uint32_t quota_lo; /* quota limit low bytes */
379 uint32_t quota_hi; /* quota limit high bytes */
380};
381
382struct ipa_uc_quota_ind {
383 uint64_t quota_bytes; /* quota limit in bytes */
384};
385#endif
386
Yun Park52b2b992016-09-22 15:49:51 -0700387/**
388 * struct hdd_ipa_tx_desc
389 * @link: link to list head
390 * @priv: pointer to priv list entry
391 * @id: Tx desc idex
392 * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor
393 */
394struct hdd_ipa_tx_desc {
395 struct list_head link;
396 void *priv;
397 uint32_t id;
Yun Park6c86a662017-10-05 16:09:15 -0700398 qdf_ipa_rx_data_t *ipa_tx_desc_ptr;
Yun Park52b2b992016-09-22 15:49:51 -0700399};
400
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800401struct hdd_ipa_priv {
402 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
403 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
404 uint8_t num_iface;
405 enum hdd_ipa_rm_state rm_state;
406 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530407 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800408 * APIs as it is taken care gracefully. Without this, kernel would throw
409 * an warning if spin_lock_bh is used while IRQ is disabled
410 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530411 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800412 struct uc_rm_work_struct uc_rm_work;
413 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530414 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800415 struct delayed_work wake_lock_work;
416 bool wake_lock_released;
417
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800418 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530419 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800420 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530421 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800422 bool suspended;
423
Yun Park52b2b992016-09-22 15:49:51 -0700424 qdf_spinlock_t q_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800425
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800426 struct list_head pend_desc_head;
Yun Park52b2b992016-09-22 15:49:51 -0700427 struct hdd_ipa_tx_desc *tx_desc_list;
428 struct list_head free_tx_desc_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800429
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700430 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431 struct hdd_ipa_stats stats;
432
433 struct notifier_block ipv4_notifier;
434 uint32_t curr_prod_bw;
435 uint32_t curr_cons_bw;
436
437 uint8_t activated_fw_pipe;
438 uint8_t sap_num_connected_sta;
439 uint8_t sta_connected;
440 uint32_t tx_pipe_handle;
441 uint32_t rx_pipe_handle;
442 bool resource_loading;
443 bool resource_unloading;
444 bool pending_cons_req;
445 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530446 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530447 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700448 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800449 uint32_t ipa_tx_packets_diff;
450 uint32_t ipa_rx_packets_diff;
451 uint32_t ipa_p_tx_packets;
452 uint32_t ipa_p_rx_packets;
453 uint32_t stat_req_reason;
454 uint64_t ipa_tx_forward;
455 uint64_t ipa_rx_discard;
456 uint64_t ipa_rx_net_send_count;
Yun Park46255682017-10-09 15:56:34 -0700457 uint64_t ipa_rx_internal_drop_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800458 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530459 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800460 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
461 unsigned int rt_buf_fill_index;
Yun Park6c86a662017-10-05 16:09:15 -0700462 qdf_ipa_wdi_in_params_t cons_pipe_in;
463 qdf_ipa_wdi_in_params_t prod_pipe_in;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800464 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800465 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530466 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530467 qdf_mutex_t rt_debug_lock;
468 qdf_mutex_t ipa_lock;
Yun Parkb4f591d2017-03-29 15:51:01 -0700469
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800470 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
471 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Yun Park637d6482016-10-05 10:51:33 -0700472#ifdef FEATURE_METERING
473 struct ipa_uc_sharing_stats ipa_sharing_stats;
474 struct ipa_uc_quota_rsp ipa_quota_rsp;
475 struct ipa_uc_quota_ind ipa_quota_ind;
476 struct completion ipa_uc_sharing_stats_comp;
477 struct completion ipa_uc_set_quota_comp;
478#endif
Yun Park777d7242017-03-30 15:38:33 -0700479 struct completion ipa_resource_comp;
Yun Park84c0ceb2018-01-11 10:37:10 -0800480
481 uint32_t wdi_version;
482 bool is_smmu_enabled; /* IPA caps returned from ipa_wdi_init */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800483};
484
Leo Changcc923e22016-06-16 15:29:03 -0700485#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
486#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800487#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
488#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
489#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
490#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
491#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
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 { \
Yun Parkec845302016-12-15 09:22:57 -0800508 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \
509 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _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
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800515#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
516
Yun Park0dad1002017-07-14 14:57:01 -0700517#define HDD_IPA_DBG_DUMP_RX_LEN 84
Yun Parkb187d542016-11-14 18:10:04 -0800518#define HDD_IPA_DBG_DUMP_TX_LEN 48
519
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800520static struct hdd_ipa_adapter_2_client {
Yun Park6c86a662017-10-05 16:09:15 -0700521 qdf_ipa_client_type_t cons_client;
522 qdf_ipa_client_type_t prod_client;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800523} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
524 {
525 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
526 }, {
527 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
528 }, {
529 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
530 },
531};
532
Yun Park637d6482016-10-05 10:51:33 -0700533#ifdef FEATURE_METERING
534#define IPA_UC_SHARING_STATES_WAIT_TIME 500
535#define IPA_UC_SET_QUOTA_WAIT_TIME 500
536#endif
537
Yun Park777d7242017-03-30 15:38:33 -0700538#define IPA_RESOURCE_COMP_WAIT_TIME 100
539
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800540static struct hdd_ipa_priv *ghdd_ipa;
541
542/* Local Function Prototypes */
Yun Park6c86a662017-10-05 16:09:15 -0700543static void hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800544 unsigned long data);
Yun Park6c86a662017-10-05 16:09:15 -0700545static void hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800546 unsigned long data);
Yun Parkb4f591d2017-03-29 15:51:01 -0700547#ifdef FEATURE_METERING
Yun Park6c86a662017-10-05 16:09:15 -0700548static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Parkb4f591d2017-03-29 15:51:01 -0700549 void *data);
550#else
551static void hdd_ipa_wdi_meter_notifier_cb(void);
552#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800553static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800554
555static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Yun Parka4bb37c2017-12-08 16:14:22 -0800556static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa,
557 bool is_loading);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800558
Yun Park84c0ceb2018-01-11 10:37:10 -0800559static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa);
560static int hdd_ipa_wdi_init(struct hdd_ipa_priv *hdd_ipa);
561
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800562/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800563 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
564 * @priv_ctxt: hdd ipa local context
565 *
566 * Will be called by IPA context.
567 * It's atomic context, then should be scheduled to kworker thread
568 *
569 * Return: None
570 */
571static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
572{
573 struct hdd_ipa_priv *hdd_ipa;
574 struct op_msg_type *msg;
575 struct uc_op_work_struct *uc_op_work;
576
577 if (priv_ctxt == NULL) {
578 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
579 return;
580 }
581
582 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
Yun Park6edb2172018-01-14 00:18:05 -0800583 hdd_ipa->uc_loaded = true;
584
585 uc_op_work = &hdd_ipa->uc_op_work[HDD_IPA_UC_OPCODE_UC_READY];
586
587 if (!list_empty(&uc_op_work->work.entry))
588 /* uc_op_work is not initialized yet */
589 return;
590
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800591 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
592 if (!msg) {
593 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
594 return;
595 }
596
597 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
598
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800599 /* When the same uC OPCODE is already pended, just return */
600 if (uc_op_work->msg)
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530601 goto done;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800602
603 uc_op_work->msg = msg;
604 schedule_work(&uc_op_work->work);
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530605
jiadd91a6842017-08-01 14:46:02 +0800606 /* work handler will free the msg buffer */
607 return;
608
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530609done:
610 qdf_mem_free(msg);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800611}
612
613/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800614 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
615 * @ctrl: WDI control value
616 *
617 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
618 *
619 * Return: 0 on message send to ipa, -1 on failure
620 */
621static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
622{
Yun Park6c86a662017-10-05 16:09:15 -0700623 qdf_ipa_msg_meta_t meta;
624 qdf_ipa_wlan_msg_t *ipa_msg;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800625 int ret = 0;
626
627 /* WDI enable message to IPA */
Yun Park6c86a662017-10-05 16:09:15 -0700628 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg);
629 ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800630 if (ipa_msg == NULL) {
631 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
632 "msg allocation failed");
633 return -ENOMEM;
634 }
635
636 if (ctrl == true)
Yun Park6c86a662017-10-05 16:09:15 -0700637 QDF_IPA_MSG_META_MSG_TYPE(&meta) = WLAN_WDI_ENABLE;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800638 else
Yun Park6c86a662017-10-05 16:09:15 -0700639 QDF_IPA_MSG_META_MSG_TYPE(&meta) = WLAN_WDI_DISABLE;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800640
Srinivas Girigowda97852372017-03-06 16:52:59 -0800641 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park6c86a662017-10-05 16:09:15 -0700642 "ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
643 ret = qdf_ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800644 if (ret) {
645 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
646 "ipa_send_msg(Evt:%d)-fail=%d",
Yun Park6c86a662017-10-05 16:09:15 -0700647 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800648 qdf_mem_free(ipa_msg);
649 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800650 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800651}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800652
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800653/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800654 * hdd_ipa_is_enabled() - Is IPA enabled?
655 * @hdd_ctx: Global HDD context
656 *
657 * Return: true if IPA is enabled, false otherwise
658 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700659bool hdd_ipa_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800660{
661 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
662}
663
664/**
665 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
666 * @hdd_ctx: Global HDD context
667 *
668 * Return: true if IPA uC offload is enabled, false otherwise
669 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700670bool hdd_ipa_uc_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800671{
672 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
673}
674
675/**
676 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
677 * @hdd_ctx: Global HDD context
678 *
679 * Return: true if STA mode IPA uC offload is enabled, false otherwise
680 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700681static inline bool hdd_ipa_uc_sta_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800682{
683 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
684}
685
686/**
Guolei Bianca144d82016-11-10 11:07:42 +0800687 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
688 * @hdd_ipa: Global HDD IPA context
689 *
690 * Return: None
691 */
Guolei Bianca144d82016-11-10 11:07:42 +0800692static inline void hdd_ipa_uc_sta_reset_sta_connected(
693 struct hdd_ipa_priv *hdd_ipa)
694{
Yun Park637d6482016-10-05 10:51:33 -0700695 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800696 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700697 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800698}
Guolei Bianca144d82016-11-10 11:07:42 +0800699
700/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800701 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
702 * @hdd_ipa: Global HDD IPA context
703 *
704 * Return: true if pre-filter is enabled, otherwise false
705 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700706static inline bool hdd_ipa_is_pre_filter_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800707{
708 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
709 HDD_IPA_PRE_FILTER_ENABLE_MASK);
710}
711
712/**
713 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
714 * @hdd_ipa: Global HDD IPA context
715 *
716 * Return: true if IPv6 is enabled, otherwise false
717 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700718static inline bool hdd_ipa_is_ipv6_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800719{
720 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
721}
722
723/**
724 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
725 * @hdd_ipa: Global HDD IPA context
726 *
727 * Return: true if resource manager is enabled, otherwise false
728 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700729static inline bool hdd_ipa_is_rm_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800730{
731 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
732}
733
734/**
735 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
736 * @hdd_ipa: Global HDD IPA context
737 *
738 * Return: true if resource manager is enabled, otherwise false
739 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700740static inline bool hdd_ipa_is_rt_debugging_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800741{
742 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
743}
744
745/**
746 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
747 * @hdd_ipa: Global HDD IPA context
748 *
749 * Return: true if clock scaling is enabled, otherwise false
750 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700751static inline bool hdd_ipa_is_clk_scaling_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800752{
753 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
754 HDD_IPA_CLK_SCALING_ENABLE_MASK |
755 HDD_IPA_RM_ENABLE_MASK);
756}
757
Yun Park84c0ceb2018-01-11 10:37:10 -0800758#ifdef FEATURE_METERING
759/**
760 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
761 * IPA calls to get WLAN stats or set quota limit.
762 * @priv: pointer to private data registered with IPA (we register a
763 *» pointer to the global IPA context)
764 * @evt: the IPA event which triggered the callback
765 * @data: data associated with the event
766 *
767 * Return: None
768 */
769static void __hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
770 void *data)
771{
772 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
773 struct hdd_adapter *adapter = NULL;
774 qdf_ipa_get_wdi_sap_stats_t *wdi_sap_stats;
775 qdf_ipa_set_wifi_quota_t *ipa_set_quota;
776 int ret = 0;
777
778 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
779 return;
780
781 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
782
783 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
784
785 switch (evt) {
786 case IPA_GET_WDI_SAP_STATS:
787 /* fill-up ipa_get_wdi_sap_stats structure after getting
788 * ipa_uc_fw_stats from FW
789 */
790 wdi_sap_stats = data;
791
792 if (!adapter) {
793 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
794 "IPA uC share stats failed - no adapter");
795 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) =
796 0;
797 return;
798 }
799
800 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
801 hdd_ipa_uc_sharing_stats_request(
802 adapter,
803 QDF_IPA_GET_WDI_SAP_STATS_RESET_STATS(wdi_sap_stats));
804 ret = wait_for_completion_timeout(
805 &hdd_ipa->ipa_uc_sharing_stats_comp,
806 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
807 if (!ret) {
808 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
809 "IPA uC share stats request timed out");
810 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
811 = 0;
812 } else {
813 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
814 = 1;
815
816 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(wdi_sap_stats)
817 = hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
818 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(wdi_sap_stats)
819 = hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
820 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(wdi_sap_stats)
821 = hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
822 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(wdi_sap_stats)
823 = hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
824 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(wdi_sap_stats)
825 = hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
826 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(wdi_sap_stats)
827 = hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
828 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(wdi_sap_stats)
829 = hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
830 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(wdi_sap_stats)
831 = hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
832 HDD_IPA_DP_LOG(
833 QDF_TRACE_LEVEL_DEBUG,
834 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
835 "IPA_GET_WDI_SAP_STATS",
836 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(
837 wdi_sap_stats),
838 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(
839 wdi_sap_stats),
840 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(
841 wdi_sap_stats),
842 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(
843 wdi_sap_stats),
844 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(
845 wdi_sap_stats),
846 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(
847 wdi_sap_stats),
848 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(
849 wdi_sap_stats),
850 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(
851 wdi_sap_stats),
852 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(
853 wdi_sap_stats));
854 }
855 break;
856 case IPA_SET_WIFI_QUOTA:
857 /* get ipa_set_wifi_quota structure from IPA and pass to FW
858 * through quota_exceeded field in ipa_uc_fw_stats
859 */
860 ipa_set_quota = data;
861
862 if (!adapter) {
863 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
864 "IPA uC set quota failed - no adapter");
865 ipa_set_quota->set_valid = 0;
866 return;
867 }
868
869 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
870 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
871 ipa_set_quota->quota_bytes);
872
873 ret = wait_for_completion_timeout(
874 &hdd_ipa->ipa_uc_set_quota_comp,
875 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
876 if (!ret) {
877 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
878 "IPA uC set quota request timed out");
879 QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = 0;
880 } else {
881 QDF_IPA_SET_WIFI_QUOTA_BYTES(ipa_set_quota) =
882 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
883 << 32) | hdd_ipa->ipa_quota_rsp.quota_lo;
884 QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) =
885 hdd_ipa->ipa_quota_rsp.success;
886 }
887
888 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
889 ipa_set_quota->quota_bytes,
890 ipa_set_quota->set_valid);
891 break;
892 }
893}
894
895/**
896 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
897 * IPA calls to get WLAN stats or set quota limit.
898 * @priv: pointer to private data registered with IPA (we register a
899 * pointer to the global IPA context)
900 * @evt: the IPA event which triggered the callback
901 * @data: data associated with the event
902 *
903 * Return: None
904 */
905static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
906 void *data)
907{
908 cds_ssr_protect(__func__);
909 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
910 cds_ssr_unprotect(__func__);
911}
912
913static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
914{
915 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
916 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
917}
918#else /* FEATURE_METERING */
919static void hdd_ipa_wdi_meter_notifier_cb(void)
920{
921}
922
923static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
924{
925}
926#endif /* FEATURE_METERING */
927
928#ifdef CONFIG_IPA_WDI_UNIFIED_API
929
930/*
931 * TODO: Get WDI version through FW capabilities
932 */
933#ifdef CONFIG_LITHIUM
934static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa)
935{
936 hdd_ipa->wdi_version = IPA_WDI_3;
937}
938#elif defined(QCA_WIFI_3_0)
939static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa)
940{
941 hdd_ipa->wdi_version = IPA_WDI_2;
942}
943#else
944static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa)
945{
946 hdd_ipa->wdi_version = IPA_WDI_1;
947}
948#endif
949
950static inline bool hdd_ipa_wdi_is_smmu_enabled(struct hdd_ipa_priv *hdd_ipa,
951 qdf_device_t osdev)
952{
953 /* TODO: Need to check if SMMU is supported on cld_3.2 */
954 /* return hdd_ipa->is_smmu_enabled && qdf_mem_smmu_s1_enabled(osdev); */
955 return 0;
956}
957
958static inline QDF_STATUS hdd_ipa_wdi_setup(struct hdd_ipa_priv *hdd_ipa)
959{
960 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
961 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
962 qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
963 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
964 qdf_ipa_sys_connect_params_t sys_in[HDD_IPA_MAX_IFACE];
965 int i;
966
967 for (i = 0; i < HDD_IPA_MAX_IFACE; i++)
968 memcpy(&sys_in[i],
969 &hdd_ipa->sys_pipe[i].ipa_sys_params,
970 sizeof(qdf_ipa_sys_connect_params_t));
971
972 return cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
973 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
974 hdd_ipa_wdi_meter_notifier_cb,
975 hdd_ctx->config->IpaDescSize,
976 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
977 &hdd_ipa->tx_pipe_handle,
978 &hdd_ipa->rx_pipe_handle,
979 hdd_ipa_wdi_is_smmu_enabled(hdd_ipa, osdev),
980 sys_in);
981}
982
983#ifdef FEATURE_METERING
984static inline void hdd_ipa_wdi_init_metering(struct hdd_ipa_priv *ipa_ctxt, void *in)
985{
986 qdf_ipa_wdi_init_in_params_t *wdi3_in;
987
988 wdi3_in = (qdf_ipa_wdi_init_in_params_t *)in;
989 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(wdi3_in) =
990 hdd_ipa_wdi_meter_notifier_cb;
991}
992#else
993static inline void hdd_ipa_wdi_init_metering(struct hdd_ipa_priv *ipa_ctxt, void *in)
994{
995}
996#endif
997
998static inline int hdd_ipa_wdi_init(struct hdd_ipa_priv *hdd_ipa)
999{
1000 qdf_ipa_wdi_init_in_params_t in;
1001 qdf_ipa_wdi_init_out_params_t out;
1002 int ret;
1003
1004 hdd_ipa->uc_loaded = false;
1005
1006 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = hdd_ipa->wdi_version;
1007 QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = hdd_ipa_uc_loaded_uc_cb;
1008 QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = (void *)hdd_ipa;
1009 hdd_ipa_wdi_init_metering(hdd_ipa, (void *)&in);
1010
1011 ret = qdf_ipa_wdi_init(&in, &out);
1012 if (ret) {
1013 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1014 "ipa_wdi_init failed with ret=%d", ret);
1015 return -EPERM;
1016 }
1017
1018 if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) {
1019 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "IPA uC READY");
1020 hdd_ipa->uc_loaded = true;
1021 hdd_ipa->is_smmu_enabled =
1022 QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
1023 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "is_smmu_enabled=%d",
1024 hdd_ipa->is_smmu_enabled);
1025 } else {
1026 ret = -EACCES;
1027 }
1028
1029 return ret;
1030}
1031
1032static inline int hdd_ipa_wdi_cleanup(void)
1033{
1034 int ret;
1035
1036 ret = qdf_ipa_wdi_cleanup();
1037 if (ret)
1038 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1039 "ipa_wdi_cleanup failed ret=%d", ret);
1040 return ret;
1041}
1042
1043static inline int hdd_ipa_wdi_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
1044 struct ipa_sys_connect_params *sys,
1045 uint32_t *handle)
1046{
1047 return 0;
1048}
1049
1050static inline int hdd_ipa_wdi_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
1051 uint32_t handle)
1052{
1053 return 0;
1054}
1055
1056static inline int hdd_ipa_wdi_rm_request_resource(
1057 struct hdd_ipa_priv *hdd_ipa,
1058 enum ipa_rm_resource_name res_name)
1059{
1060 return 0;
1061}
1062
1063static inline int hdd_ipa_wdi_rm_release_resource(
1064 struct hdd_ipa_priv *hdd_ipa,
1065 enum ipa_rm_resource_name res_name)
1066{
1067 return 0;
1068}
1069
1070static inline int hdd_ipa_wdi_setup_rm(struct hdd_ipa_priv *hdd_ipa)
1071{
1072 return 0;
1073}
1074
1075static inline int hdd_ipa_wdi_destroy_rm(struct hdd_ipa_priv *hdd_ipa)
1076{
1077 return 0;
1078}
1079
1080static inline int hdd_ipa_wdi_rm_request(struct hdd_ipa_priv *hdd_ipa)
1081{
1082 return 0;
1083}
1084
1085static inline int hdd_ipa_wdi_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
1086{
1087 return 0;
1088}
1089
1090static inline int hdd_ipa_wdi_rm_notify_completion(
1091 enum ipa_rm_event event,
1092 enum ipa_rm_resource_name resource_name)
1093{
1094 return 0;
1095}
1096
1097#else /* CONFIG_IPA_WDI_UNIFIED_API */
1098
1099static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa)
1100{
1101}
1102
1103static inline int hdd_ipa_wdi_is_smmu_enabled(struct hdd_ipa_priv *hdd_ipa,
1104 qdf_device_t osdev)
1105{
1106 /* TODO: Need to check if SMMU is supported on cld_3.2 */
1107 /* return qdf_mem_smmu_s1_enabled(osdev); */
1108 return 0;
1109}
1110
1111static inline QDF_STATUS hdd_ipa_wdi_setup(struct hdd_ipa_priv *hdd_ipa)
1112{
1113 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1114 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
1115 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
1116
1117 return cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
1118 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
1119 hdd_ipa_wdi_meter_notifier_cb,
1120 hdd_ctx->config->IpaDescSize,
1121 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
1122 &hdd_ipa->tx_pipe_handle,
1123 &hdd_ipa->rx_pipe_handle);
1124}
1125
1126static inline int hdd_ipa_wdi_init(struct hdd_ipa_priv *hdd_ipa)
1127{
1128 struct ipa_wdi_uc_ready_params uc_ready_param;
1129 int ret = 0;
1130
1131 hdd_ipa->uc_loaded = false;
1132 uc_ready_param.priv = (void *)hdd_ipa;
1133 uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
1134 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
1135 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1136 "UC Ready CB register fail");
1137 return -EPERM;
1138 }
1139
1140 if (true == uc_ready_param.is_uC_ready) {
1141 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
1142 hdd_ipa->uc_loaded = true;
1143 } else {
1144 ret = -EACCES;
1145 }
1146
1147 return ret;
1148}
1149
1150static inline int hdd_ipa_wdi_cleanup(void)
1151{
1152 int ret;
1153
1154 ret = ipa_uc_dereg_rdyCB();
1155 if (ret)
1156 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1157 "UC Ready CB deregister fail");
1158 return ret;
1159}
1160
1161static inline int hdd_ipa_wdi_setup_sys_pipe(
1162 struct hdd_ipa_priv *hdd_ipa,
1163 struct ipa_sys_connect_params *sys, uint32_t *handle)
1164{
1165 return qdf_ipa_setup_sys_pipe(sys, handle);
1166}
1167
1168static inline int hdd_ipa_wdi_teardown_sys_pipe(
1169 struct hdd_ipa_priv *hdd_ipa,
1170 uint32_t handle)
1171{
1172 return qdf_ipa_teardown_sys_pipe(handle);
1173}
1174
1175static inline int hdd_ipa_wdi_rm_request_resource(
1176 struct hdd_ipa_priv *hdd_ipa,
1177 enum ipa_rm_resource_name res_name)
1178{
1179 return qdf_ipa_rm_request_resource(res_name);
1180}
1181
1182static inline int hdd_ipa_wdi_rm_release_resource(
1183 struct hdd_ipa_priv *hdd_ipa,
1184 enum ipa_rm_resource_name res_name)
1185{
1186 return qdf_ipa_rm_release_resource(res_name);
1187}
1188
1189/**
1190 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
1191 * @work: struct work_struct
1192 * @work_handler: work_handler
1193 *
1194 * Return: none
1195 */
1196static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
1197 work_func_t work_handler)
1198{
1199 INIT_WORK(work, work_handler);
1200}
1201
1202/**
1203 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
1204 * @work: scheduled work
1205 *
1206 * When IPA resources are released in hdd_ipa_wdi_rm_try_release() we do
1207 * not want to immediately release the wake lock since the system
1208 * would then potentially try to suspend when there is a healthy data
1209 * rate. Deferred work is scheduled and this function handles the
1210 * work. When this function is called, if the IPA resource is still
1211 * released then we release the wake lock.
1212 *
1213 * Return: None
1214 */
1215static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
1216{
1217 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
1218 struct hdd_ipa_priv,
1219 wake_lock_work);
1220
1221 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
1222
1223 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
1224 goto end;
1225
1226 hdd_ipa->wake_lock_released = true;
1227 qdf_wake_lock_release(&hdd_ipa->wake_lock,
1228 WIFI_POWER_EVENT_WAKELOCK_IPA);
1229
1230end:
1231 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1232}
1233
1234/**
1235 * hdd_ipa_wdi_rm_request() - Request resource from IPA
1236 * @hdd_ipa: Global HDD IPA context
1237 *
1238 * Return: 0 on success, negative errno on error
1239 */
1240static int hdd_ipa_wdi_rm_request(struct hdd_ipa_priv *hdd_ipa)
1241{
1242 int ret = 0;
1243
1244 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1245 return 0;
1246
1247 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
1248
1249 switch (hdd_ipa->rm_state) {
1250 case HDD_IPA_RM_GRANTED:
1251 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1252 return 0;
1253 case HDD_IPA_RM_GRANT_PENDING:
1254 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1255 return -EINPROGRESS;
1256 case HDD_IPA_RM_RELEASED:
1257 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
1258 break;
1259 }
1260
1261 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1262
1263 ret = qdf_ipa_rm_inactivity_timer_request_resource(
1264 IPA_RM_RESOURCE_WLAN_PROD);
1265
1266 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
1267 if (ret == 0) {
1268 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
1269 hdd_ipa->stats.num_rm_grant_imm++;
1270 }
1271
1272 cancel_delayed_work(&hdd_ipa->wake_lock_work);
1273 if (hdd_ipa->wake_lock_released) {
1274 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
1275 WIFI_POWER_EVENT_WAKELOCK_IPA);
1276 hdd_ipa->wake_lock_released = false;
1277 }
1278 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1279
1280 return ret;
1281}
1282
1283/**
1284 * hdd_ipa_wdi_rm_try_release() - Attempt to release IPA resource
1285 * @hdd_ipa: Global HDD IPA context
1286 *
1287 * Return: 0 if resources released, negative errno otherwise
1288 */
1289static int hdd_ipa_wdi_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
1290{
1291 int ret = 0;
1292
1293 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1294 return 0;
1295
1296 if (atomic_read(&hdd_ipa->tx_ref_cnt))
1297 return -EAGAIN;
1298
1299 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
1300
1301 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
1302 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
1303 return -EAGAIN;
1304 }
1305 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
1306
1307 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
1308 switch (hdd_ipa->rm_state) {
1309 case HDD_IPA_RM_GRANTED:
1310 break;
1311 case HDD_IPA_RM_GRANT_PENDING:
1312 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1313 return -EINPROGRESS;
1314 case HDD_IPA_RM_RELEASED:
1315 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1316 return 0;
1317 }
1318
1319 /* IPA driver returns immediately so set the state here to avoid any
1320 * race condition.
1321 */
1322 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
1323 hdd_ipa->stats.num_rm_release++;
1324 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1325
1326 ret = qdf_ipa_rm_inactivity_timer_release_resource(
1327 IPA_RM_RESOURCE_WLAN_PROD);
1328
1329 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
1330 if (unlikely(ret != 0)) {
1331 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
1332 WARN_ON(1);
1333 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
1334 "ipa_rm_inactivity_timer_release_resource returnied fail");
1335 }
1336
1337 /*
1338 * If wake_lock is released immediately, kernel would try to suspend
1339 * immediately as well, Just avoid ping-pong between suspend-resume
1340 * while there is healthy amount of data transfer going on by
1341 * releasing the wake_lock after some delay.
1342 */
1343 schedule_delayed_work(&hdd_ipa->wake_lock_work,
1344 msecs_to_jiffies
1345 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
1346
1347 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1348
1349 return ret;
1350}
1351
1352/**
1353 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
1354 * @user_data: user data registered with IPA
1355 * @event: the IPA resource manager event that occurred
1356 * @data: the data associated with the event
1357 *
1358 * Return: None
1359 */
1360static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
1361 unsigned long data)
1362{
1363 struct hdd_ipa_priv *hdd_ipa = user_data;
1364
1365 if (unlikely(!hdd_ipa))
1366 return;
1367
1368 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1369 return;
1370
1371 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
1372
1373 switch (event) {
1374 case IPA_RM_RESOURCE_GRANTED:
1375 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
1376 /* RM Notification comes with ISR context
1377 * it should be serialized into work queue to avoid
1378 * ISR sleep problem
1379 */
1380 hdd_ipa->uc_rm_work.event = event;
1381 schedule_work(&hdd_ipa->uc_rm_work.work);
1382 break;
1383 }
1384 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
1385 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
1386 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
1387 hdd_ipa->stats.num_rm_grant++;
1388 break;
1389
1390 case IPA_RM_RESOURCE_RELEASED:
1391 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
1392 hdd_ipa->resource_unloading = false;
1393 break;
1394
1395 default:
1396 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
1397 break;
1398 }
1399}
1400
1401/**
1402 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
1403 *
1404 * Callback function registered with IPA that is called when IPA wants
1405 * to release the WLAN consumer resource
1406 *
1407 * Return: 0 if the request is granted, negative errno otherwise
1408 */
1409static int hdd_ipa_rm_cons_release(void)
1410{
1411 return 0;
1412}
1413
1414/**
1415 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
1416 *
1417 * Callback function registered with IPA that is called when IPA wants
1418 * to access the WLAN consumer resource
1419 *
1420 * Return: 0 if the request is granted, negative errno otherwise
1421 */
1422static int hdd_ipa_rm_cons_request(void)
1423{
1424 int ret = 0;
1425
1426 if (ghdd_ipa->resource_loading) {
1427 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
1428 "IPA resource loading in progress");
1429 ghdd_ipa->pending_cons_req = true;
1430 ret = -EINPROGRESS;
1431 } else if (ghdd_ipa->resource_unloading) {
1432 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
1433 "IPA resource unloading in progress");
1434 ghdd_ipa->pending_cons_req = true;
1435 ret = -EPERM;
1436 }
1437
1438 return ret;
1439}
1440
1441/**
1442 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
1443 * @context: User context registered with TL (the IPA Global context is
1444 * registered
1445 * @rxpkt: Packet containing the notification
1446 * @staid: ID of the station associated with the packet
1447 *
1448 * Return: None
1449 */
1450static void
1451hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
1452{
1453 struct hdd_ipa_priv *hdd_ipa = context;
1454 QDF_STATUS status = QDF_STATUS_SUCCESS;
1455
1456 /*
1457 * When SSR is going on or driver is unloading, just return.
1458 */
1459 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
1460 if (status)
1461 return;
1462
1463 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1464 return;
1465
1466 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event code %d", event);
1467
1468 switch (event) {
1469 case IPA_RM_RESOURCE_GRANTED:
1470 /* Differed RM Granted */
1471 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
1472 if ((false == hdd_ipa->resource_unloading) &&
1473 (!hdd_ipa->activated_fw_pipe)) {
1474 hdd_ipa_uc_enable_pipes(hdd_ipa);
1475 }
1476 qdf_mutex_release(&hdd_ipa->ipa_lock);
1477 break;
1478
1479 case IPA_RM_RESOURCE_RELEASED:
1480 /* Differed RM Released */
1481 hdd_ipa->resource_unloading = false;
1482 break;
1483
1484 default:
1485 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1486 "invalid event code %d", event);
1487 break;
1488 }
1489}
1490
1491/**
1492 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
1493 * @hdd_ipa: Global HDD IPA context
1494 * @event: IPA resource manager event to be deferred
1495 *
1496 * This function is called when a resource manager event is received
1497 * from firmware in interrupt context. This function will defer the
1498 * handling to the OL RX thread
1499 *
1500 * Return: None
1501 */
1502static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
1503{
1504 enum ipa_rm_event event;
1505 struct uc_rm_work_struct *uc_rm_work = container_of(work,
1506 struct uc_rm_work_struct, work);
1507 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
1508 struct hdd_ipa_priv, uc_rm_work);
1509
1510 cds_ssr_protect(__func__);
1511 event = uc_rm_work->event;
1512 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "posted event %d", event);
1513
1514 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
1515 cds_ssr_unprotect(__func__);
1516}
1517
1518/**
1519 * hdd_ipa_wdi_setup_rm() - Setup IPA resource management
1520 * @hdd_ipa: Global HDD IPA context
1521 *
1522 * Return: 0 on success, negative errno on error
1523 */
1524static int hdd_ipa_wdi_setup_rm(struct hdd_ipa_priv *hdd_ipa)
1525{
1526 struct ipa_rm_create_params create_params = { 0 };
1527 int ret;
1528
1529 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1530 return 0;
1531
1532 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
1533 hdd_ipa_uc_rm_notify_defer);
1534 memset(&create_params, 0, sizeof(create_params));
1535 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
1536 create_params.reg_params.user_data = hdd_ipa;
1537 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
1538 create_params.floor_voltage = IPA_VOLTAGE_SVS;
1539
1540 ret = qdf_ipa_rm_create_resource(&create_params);
1541 if (ret) {
1542 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1543 "Create RM resource failed: %d", ret);
1544 goto setup_rm_fail;
1545 }
1546
1547 memset(&create_params, 0, sizeof(create_params));
1548 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
1549 create_params.request_resource = hdd_ipa_rm_cons_request;
1550 create_params.release_resource = hdd_ipa_rm_cons_release;
1551 create_params.floor_voltage = IPA_VOLTAGE_SVS;
1552
1553 ret = qdf_ipa_rm_create_resource(&create_params);
1554 if (ret) {
1555 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1556 "Create RM CONS resource failed: %d", ret);
1557 goto delete_prod;
1558 }
1559
1560 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
1561 IPA_RM_RESOURCE_APPS_CONS);
1562
1563 ret = qdf_ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
1564 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
1565 if (ret) {
1566 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
1567 ret);
1568 goto timer_init_failed;
1569 }
1570
1571 /* Set the lowest bandwidth to start with */
1572 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
1573
1574 if (ret) {
1575 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1576 "Set perf level failed: %d", ret);
1577 goto set_perf_failed;
1578 }
1579
1580 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
1581 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
1582 hdd_ipa_wake_lock_timer_func);
1583 qdf_spinlock_create(&hdd_ipa->rm_lock);
1584 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
1585 hdd_ipa->wake_lock_released = true;
1586 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
1587
1588 return ret;
1589
1590set_perf_failed:
1591 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
1592
1593timer_init_failed:
1594 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
1595
1596delete_prod:
1597 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
1598
1599setup_rm_fail:
1600 return ret;
1601}
1602
1603/**
1604 * hdd_ipa_wdi_destroy_rm() - Destroy IPA resources
1605 * @hdd_ipa: Global HDD IPA context
1606 *
1607 * Destroys all resources associated with the IPA resource manager
1608 *
1609 * Return: None
1610 */
1611static void hdd_ipa_wdi_destroy_rm(struct hdd_ipa_priv *hdd_ipa)
1612{
1613 int ret;
1614
1615 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1616 return;
1617
1618 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
1619 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
1620 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
1621 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
1622
1623 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
1624
1625 ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
1626 if (ret)
1627 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1628 "RM PROD resource delete failed %d", ret);
1629
1630 ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
1631 if (ret)
1632 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1633 "RM CONS resource delete failed %d", ret);
1634}
1635
1636static int hdd_ipa_wdi_rm_notify_completion(enum ipa_rm_event event,
1637 enum ipa_rm_resource_name resource_name)
1638{
1639 return qdf_ipa_rm_notify_completion(event, resource_name);
1640}
1641#endif /* CONFIG_IPA_WDI_UNIFIED_API */
1642
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001643/**
1644 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
1645 * @ctext: pointer to hdd context.
1646 *
1647 * If rt debug enabled, periodically called, and fill debug buffer
1648 *
1649 * Return: none
1650 */
1651static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
1652{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001653 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654 struct hdd_ipa_priv *hdd_ipa;
1655 struct uc_rt_debug_info *dump_info = NULL;
1656
1657 if (wlan_hdd_validate_context(hdd_ctx))
1658 return;
1659
1660 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001661 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001662 return;
1663 }
1664
1665 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1666
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301667 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668 dump_info = &hdd_ipa->rt_bug_buffer[
1669 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
1670
Deepthi Gowri6acee342016-10-28 15:00:38 +05301671 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
Yun Park46255682017-10-09 15:56:34 -07001673 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internal_drop_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001674 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001675 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -08001676 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
1677 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001678 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
1679 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301680 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001681
Anurag Chouhan210db072016-02-22 18:42:15 +05301682 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Yun Park84c0ceb2018-01-11 10:37:10 -08001683 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001684}
1685
1686/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001687 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 * @hdd_ctx: pointer to hdd context.
1689 *
1690 * If rt debug enabled, dump debug buffer contents based on requirement
1691 *
1692 * Return: none
1693 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001694static void __hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695{
1696 struct hdd_ipa_priv *hdd_ipa;
1697 unsigned int dump_count;
1698 unsigned int dump_index;
1699 struct uc_rt_debug_info *dump_info = NULL;
1700
1701 if (wlan_hdd_validate_context(hdd_ctx))
1702 return;
1703
1704 hdd_ipa = hdd_ctx->hdd_ipa;
1705 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001706 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001707 return;
1708 }
1709
Chris Guo1751acf2017-07-03 14:09:01 +08001710 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
1711 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park84c0ceb2018-01-11 10:37:10 -08001712 "IPA RT debug is not enabled");
Chris Guo1751acf2017-07-03 14:09:01 +08001713 return;
1714 }
1715
Yun Park46255682017-10-09 15:56:34 -07001716 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park84c0ceb2018-01-11 10:37:10 -08001717 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Yun Park46255682017-10-09 15:56:34 -07001718 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park84c0ceb2018-01-11 10:37:10 -08001719 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301721 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 for (dump_count = 0;
1723 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
1724 dump_count++) {
1725 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
1726 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
1727 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Yun Park46255682017-10-09 15:56:34 -07001728 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park84c0ceb2018-01-11 10:37:10 -08001729 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
1730 dump_info->time, dump_info->ipa_excep_count,
1731 dump_info->rx_drop_count, dump_info->net_sent_count,
1732 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
1733 dump_info->rx_destructor_call,
1734 dump_info->rx_discard_count);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001735 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301736 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Yun Park46255682017-10-09 15:56:34 -07001737 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park84c0ceb2018-01-11 10:37:10 -08001738 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001739}
1740
1741/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001742 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
1743 * __hdd_ipa_uc_rt_debug_host_dump
1744 * @hdd_ctx: pointer to hdd context.
1745 *
1746 * If rt debug enabled, dump debug buffer contents based on requirement
1747 *
1748 * Return: none
1749 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001750void hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001751{
1752 cds_ssr_protect(__func__);
1753 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1754 cds_ssr_unprotect(__func__);
1755}
1756
1757/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
1759 * @ctext: pointer to hdd context.
1760 *
1761 * periodically called by timer expire
1762 * will try to alloc dummy memory and detect out of memory condition
1763 * if out of memory detected, dump wlan-ipa stats
1764 *
1765 * Return: none
1766 */
1767static void hdd_ipa_uc_rt_debug_handler(void *ctext)
1768{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001769 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001770 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001771 void *dummy_ptr = NULL;
1772
1773 if (wlan_hdd_validate_context(hdd_ctx))
1774 return;
1775
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001776 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1777
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001778 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001779 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1780 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001781 return;
1782 }
1783
1784 /* Allocate dummy buffer periodically and free immediately. this will
1785 * proactively detect OOM and if allocation fails dump ipa stats
1786 */
1787 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
1788 GFP_KERNEL | GFP_ATOMIC);
1789 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001790 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
1791 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -07001792 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
1793 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794 } else {
1795 kfree(dummy_ptr);
1796 }
1797
Anurag Chouhan210db072016-02-22 18:42:15 +05301798 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001799 HDD_IPA_UC_RT_DEBUG_PERIOD);
1800}
1801
1802/**
Yun Parkb187d542016-11-14 18:10:04 -08001803 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001804 * @skb: packet pinter
1805 *
1806 * when free data packet, will be invoked by wlan client and will increase
1807 * free counter
1808 *
1809 * Return: none
1810 */
Jeff Johnsond7720632016-10-05 16:04:32 -07001811static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812{
1813 if (!ghdd_ipa) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001814 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "invalid hdd context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001815 return;
1816 }
1817
1818 ghdd_ipa->ipa_rx_destructor_count++;
1819}
1820
1821/**
Yun Parkb187d542016-11-14 18:10:04 -08001822 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001823 * @hdd_ctx: hdd main context
1824 *
1825 * free all rt debugging resources
1826 *
1827 * Return: none
1828 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001829static void hdd_ipa_uc_rt_debug_deinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001831 struct hdd_ipa_priv *hdd_ipa;
1832
1833 if (wlan_hdd_validate_context(hdd_ctx))
1834 return;
1835
1836 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001837
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301838 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839
1840 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001841 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1842 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001843 return;
1844 }
1845
Anurag Chouhan210db072016-02-22 18:42:15 +05301846 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001847 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1848 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1849 }
1850 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1851
1852 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301853 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1854 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001855 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301856 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857}
1858
1859/**
Yun Parkb187d542016-11-14 18:10:04 -08001860 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001861 * @hdd_ctx: hdd main context
1862 *
1863 * alloc and initialize all rt debugging resources
1864 *
1865 * Return: none
1866 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001867static void hdd_ipa_uc_rt_debug_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001868{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001869 struct hdd_ipa_priv *hdd_ipa;
1870
Chris Guo1751acf2017-07-03 14:09:01 +08001871 if (wlan_hdd_validate_context_in_loading(hdd_ctx))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001872 return;
1873
1874 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001875
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301876 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301878 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001879 sizeof(struct uc_rt_debug_info) *
1880 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1881 hdd_ipa->ipa_tx_forward = 0;
1882 hdd_ipa->ipa_rx_discard = 0;
1883 hdd_ipa->ipa_rx_net_send_count = 0;
Yun Park46255682017-10-09 15:56:34 -07001884 hdd_ipa->ipa_rx_internal_drop_count = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885 hdd_ipa->ipa_rx_destructor_count = 0;
1886
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887 /* Reatime debug enable on feature enable */
1888 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001889 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1890 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891 return;
1892 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001893
1894 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1895 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1896 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1897 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1898
Anurag Chouhan210db072016-02-22 18:42:15 +05301899 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301901 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001902 HDD_IPA_UC_RT_DEBUG_PERIOD);
1903
1904}
1905
1906/**
Yun Parkb187d542016-11-14 18:10:04 -08001907 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1908 * @hdd_ipa: HDD IPA struct
1909 *
1910 * Dump entries in struct hdd_ipa
1911 *
1912 * Return: none
1913 */
1914static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1915{
1916 int i;
1917
1918 /* HDD IPA */
Yun Park46255682017-10-09 15:56:34 -07001919 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1920 "\n==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001921 "num_iface: %d\n"
1922 "rm_state: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001923 "rm_lock: %pK\n"
1924 "uc_rm_work: %pK\n"
1925 "uc_op_work: %pK\n"
1926 "wake_lock: %pK\n"
1927 "wake_lock_work: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001928 "wake_lock_released: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001929 "tx_ref_cnt: %d\n"
1930 "pm_queue_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001931 "\thead: %pK\n"
1932 "\ttail: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001933 "\tqlen: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001934 "pm_work: %pK\n"
1935 "pm_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001936 "suspended: %d\n",
1937 hdd_ipa->num_iface,
1938 hdd_ipa->rm_state,
1939 &hdd_ipa->rm_lock,
1940 &hdd_ipa->uc_rm_work,
1941 &hdd_ipa->uc_op_work,
1942 &hdd_ipa->wake_lock,
1943 &hdd_ipa->wake_lock_work,
1944 hdd_ipa->wake_lock_released,
Yun Parkb187d542016-11-14 18:10:04 -08001945 hdd_ipa->tx_ref_cnt.counter,
1946 hdd_ipa->pm_queue_head.head,
1947 hdd_ipa->pm_queue_head.tail,
1948 hdd_ipa->pm_queue_head.qlen,
1949 &hdd_ipa->pm_work,
1950 &hdd_ipa->pm_lock,
1951 hdd_ipa->suspended);
Yun Park46255682017-10-09 15:56:34 -07001952
1953 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1954 "\nq_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001955 "pend_desc_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001956 "\tnext: %pK\n"
1957 "\tprev: %pK\n"
1958 "hdd_ctx: %pK\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001959 "stats: %pK\n"
1960 "ipv4_notifier: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001961 "curr_prod_bw: %d\n"
1962 "curr_cons_bw: %d\n"
1963 "activated_fw_pipe: %d\n"
1964 "sap_num_connected_sta: %d\n"
1965 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001966 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001967 hdd_ipa->pend_desc_head.next,
1968 hdd_ipa->pend_desc_head.prev,
1969 hdd_ipa->hdd_ctx,
Yun Parkb187d542016-11-14 18:10:04 -08001970 &hdd_ipa->stats,
1971 &hdd_ipa->ipv4_notifier,
1972 hdd_ipa->curr_prod_bw,
1973 hdd_ipa->curr_cons_bw,
1974 hdd_ipa->activated_fw_pipe,
1975 hdd_ipa->sap_num_connected_sta,
Yun Park46255682017-10-09 15:56:34 -07001976 (unsigned int)hdd_ipa->sta_connected);
1977
1978 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1979 "\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001980 "rx_pipe_handle: 0x%x\n"
1981 "resource_loading: %d\n"
1982 "resource_unloading: %d\n"
1983 "pending_cons_req: %d\n"
1984 "pending_event----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001985 "\tanchor.next: %pK\n"
1986 "\tanchor.prev: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001987 "\tcount: %d\n"
1988 "\tmax_size: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001989 "event_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001990 "ipa_tx_packets_diff: %d\n"
1991 "ipa_rx_packets_diff: %d\n"
1992 "ipa_p_tx_packets: %d\n"
1993 "ipa_p_rx_packets: %d\n"
1994 "stat_req_reason: %d\n",
1995 hdd_ipa->tx_pipe_handle,
1996 hdd_ipa->rx_pipe_handle,
1997 hdd_ipa->resource_loading,
1998 hdd_ipa->resource_unloading,
1999 hdd_ipa->pending_cons_req,
2000 hdd_ipa->pending_event.anchor.next,
2001 hdd_ipa->pending_event.anchor.prev,
2002 hdd_ipa->pending_event.count,
2003 hdd_ipa->pending_event.max_size,
2004 &hdd_ipa->event_lock,
2005 hdd_ipa->ipa_tx_packets_diff,
2006 hdd_ipa->ipa_rx_packets_diff,
2007 hdd_ipa->ipa_p_tx_packets,
2008 hdd_ipa->ipa_p_rx_packets,
2009 hdd_ipa->stat_req_reason);
2010
Yun Park46255682017-10-09 15:56:34 -07002011 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2012 "\ncons_pipe_in----\n"
2013 "\tsys: %pK\n"
2014 "\tdl.comp_ring_base_pa: 0x%x\n"
2015 "\tdl.comp_ring_size: %d\n"
2016 "\tdl.ce_ring_base_pa: 0x%x\n"
2017 "\tdl.ce_door_bell_pa: 0x%x\n"
2018 "\tdl.ce_ring_size: %d\n"
2019 "\tdl.num_tx_buffers: %d\n"
2020 "prod_pipe_in----\n"
2021 "\tsys: %pK\n"
2022 "\tul.rdy_ring_base_pa: 0x%x\n"
2023 "\tul.rdy_ring_size: %d\n"
2024 "\tul.rdy_ring_rp_pa: 0x%x\n"
2025 "uc_loaded: %d\n"
2026 "wdi_enabled: %d\n"
2027 "rt_debug_fill_timer: %pK\n"
2028 "rt_debug_lock: %pK\n"
2029 "ipa_lock: %pK\n",
2030 &hdd_ipa->cons_pipe_in.sys,
2031 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.comp_ring_base_pa,
2032 hdd_ipa->cons_pipe_in.u.dl.comp_ring_size,
2033 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.ce_ring_base_pa,
2034 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.ce_door_bell_pa,
2035 hdd_ipa->cons_pipe_in.u.dl.ce_ring_size,
2036 hdd_ipa->cons_pipe_in.u.dl.num_tx_buffers,
2037 &hdd_ipa->prod_pipe_in.sys,
2038 (unsigned int)hdd_ipa->prod_pipe_in.u.ul.rdy_ring_base_pa,
2039 hdd_ipa->prod_pipe_in.u.ul.rdy_ring_size,
2040 (unsigned int)hdd_ipa->prod_pipe_in.u.ul.rdy_ring_rp_pa,
2041 hdd_ipa->uc_loaded,
2042 hdd_ipa->wdi_enabled,
2043 &hdd_ipa->rt_debug_fill_timer,
2044 &hdd_ipa->rt_debug_lock,
2045 &hdd_ipa->ipa_lock);
2046
2047 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2048 "\nvdev_to_iface----");
2049 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
2050 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2051 "\n\t[%d]=%d", i, hdd_ipa->vdev_to_iface[i]);
2052 }
2053 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2054 "\nvdev_offload_enabled----");
2055 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
2056 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2057 "\n\t[%d]=%d", i, hdd_ipa->vdev_offload_enabled[i]);
2058 }
2059 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2060 "\nassoc_stas_map ----");
Yun Parkb187d542016-11-14 18:10:04 -08002061 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Yun Park46255682017-10-09 15:56:34 -07002062 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2063 "\n\t[%d]: is_reserved=%d, sta_id=%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08002064 hdd_ipa->assoc_stas_map[i].is_reserved,
2065 hdd_ipa->assoc_stas_map[i].sta_id);
2066 }
2067}
2068
2069/**
2070 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
2071 * @hdd_ipa: HDD IPA struct
2072 *
2073 * Dump entire struct hdd_ipa_sys_pipe
2074 *
2075 * Return: none
2076 */
2077static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
2078{
2079 int i;
2080
2081 /* IPA SYS Pipes */
Yun Park46255682017-10-09 15:56:34 -07002082 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2083 "\n==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08002084
2085 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
2086 struct hdd_ipa_sys_pipe *sys_pipe;
Yun Park6c86a662017-10-05 16:09:15 -07002087 qdf_ipa_sys_connect_params_t *ipa_sys_params;
Yun Parkb187d542016-11-14 18:10:04 -08002088
2089 sys_pipe = &hdd_ipa->sys_pipe[i];
2090 ipa_sys_params = &sys_pipe->ipa_sys_params;
2091
Yun Park46255682017-10-09 15:56:34 -07002092 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2093 "\nsys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08002094 "\tconn_hdl: 0x%x\n"
2095 "\tconn_hdl_valid: %d\n"
2096 "\tnat_en: %d\n"
2097 "\thdr_len %d\n"
2098 "\thdr_additional_const_len: %d\n"
2099 "\thdr_ofst_pkt_size_valid: %d\n"
2100 "\thdr_ofst_pkt_size: %d\n"
2101 "\thdr_little_endian: %d\n"
2102 "\tmode: %d\n"
2103 "\tclient: %d\n"
2104 "\tdesc_fifo_sz: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07002105 "\tpriv: %pK\n"
2106 "\tnotify: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08002107 "\tskip_ep_cfg: %d\n"
2108 "\tkeep_ipa_awake: %d\n",
2109 i,
2110 sys_pipe->conn_hdl,
2111 sys_pipe->conn_hdl_valid,
Yun Park6c86a662017-10-05 16:09:15 -07002112 QDF_IPA_SYS_PARAMS_NAT_EN(ipa_sys_params),
2113 QDF_IPA_SYS_PARAMS_HDR_LEN(ipa_sys_params),
2114 QDF_IPA_SYS_PARAMS_HDR_ADDITIONAL_CONST_LEN(
2115 ipa_sys_params),
2116 QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE_VALID(
2117 ipa_sys_params),
2118 QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE(ipa_sys_params),
2119 QDF_IPA_SYS_PARAMS_HDR_LITTLE_ENDIAN(ipa_sys_params),
2120 QDF_IPA_SYS_PARAMS_MODE(ipa_sys_params),
2121 QDF_IPA_SYS_PARAMS_CLIENT(ipa_sys_params),
2122 QDF_IPA_SYS_PARAMS_DESC_FIFO_SZ(ipa_sys_params),
2123 QDF_IPA_SYS_PARAMS_PRIV(ipa_sys_params),
2124 QDF_IPA_SYS_PARAMS_NOTIFY(ipa_sys_params),
2125 QDF_IPA_SYS_PARAMS_SKIP_EP_CFG(ipa_sys_params),
2126 QDF_IPA_SYS_PARAMS_KEEP_IPA_AWAKE(ipa_sys_params));
Yun Parkb187d542016-11-14 18:10:04 -08002127 }
2128}
2129
2130/**
2131 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
2132 * @hdd_ipa: HDD IPA struct
2133 *
2134 * Dump entire struct hdd_ipa_iface_context
2135 *
2136 * Return: none
2137 */
2138static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
2139{
2140 int i;
2141
2142 /* IPA Interface Contexts */
Yun Park46255682017-10-09 15:56:34 -07002143 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2144 "\n==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08002145
2146 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2147 struct hdd_ipa_iface_context *iface_context;
2148
2149 iface_context = &hdd_ipa->iface_context[i];
2150
Yun Park46255682017-10-09 15:56:34 -07002151 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2152 "\niface_context[%d]----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07002153 "\thdd_ipa: %pK\n"
2154 "\tadapter: %pK\n"
2155 "\ttl_context: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08002156 "\tcons_client: %d\n"
2157 "\tprod_client: %d\n"
2158 "\tiface_id: %d\n"
2159 "\tsta_id: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07002160 "\tinterface_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08002161 "\tifa_address: 0x%x\n",
2162 i,
2163 iface_context->hdd_ipa,
2164 iface_context->adapter,
2165 iface_context->tl_context,
2166 iface_context->cons_client,
2167 iface_context->prod_client,
2168 iface_context->iface_id,
2169 iface_context->sta_id,
2170 &iface_context->interface_lock,
2171 iface_context->ifa_address);
2172 }
2173}
2174
2175/**
2176 * hdd_ipa_dump_info() - dump HDD IPA struct
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07002177 * @hdd_ctx: hdd main context
Yun Parkb187d542016-11-14 18:10:04 -08002178 *
2179 * Dump entire struct hdd_ipa
2180 *
2181 * Return: none
2182 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002183void hdd_ipa_dump_info(struct hdd_context *hdd_ctx)
Yun Parkb187d542016-11-14 18:10:04 -08002184{
2185 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2186
2187 hdd_ipa_dump_hdd_ipa(hdd_ipa);
2188 hdd_ipa_dump_sys_pipe(hdd_ipa);
2189 hdd_ipa_dump_iface_context(hdd_ipa);
2190}
2191
2192/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002193 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
2194 * enabled
2195 *
2196 * This routine is called to set TX flow info if IPA is enabled
2197 *
2198 * Return: None
2199 */
2200void hdd_ipa_set_tx_flow_info(void)
2201{
Jeff Johnson49d45e62017-08-29 14:30:42 -07002202 struct hdd_adapter *adapter;
Jeff Johnsond377dce2017-10-04 10:32:42 -07002203 struct hdd_station_ctx *sta_ctx;
Jeff Johnson87251032017-08-29 13:31:11 -07002204 struct hdd_ap_ctx *hdd_ap_ctx;
Jeff Johnsonca2530c2017-09-30 18:25:40 -07002205 struct hdd_hostapd_state *hostapd_state;
Dustin Brown4e565a42018-01-17 14:59:14 -08002206 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INIT;
2207 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INIT;
2208 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INIT;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002209 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
2210 const char *p2pMode = "DEV";
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002211 struct hdd_context *hdd_ctx;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002212 cds_context_type *cds_ctx;
2213#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
2214 uint8_t targetChannel = 0;
2215 uint8_t preAdapterChannel = 0;
2216 uint8_t channel24;
2217 uint8_t channel5;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002218 struct hdd_adapter *preAdapterContext = NULL;
2219 struct hdd_adapter *adapter2_4 = NULL;
2220 struct hdd_adapter *adapter5 = NULL;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002221 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2222#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
2223 struct wlan_objmgr_psoc *psoc;
2224
2225 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
2226 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07002227 hdd_err("HDD context is NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002228 return;
2229 }
2230
2231 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
2232 if (!cds_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07002233 hdd_err("Invalid CDS Context");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002234 return;
2235 }
2236
2237 psoc = hdd_ctx->hdd_psoc;
Dustin Brown920397d2017-12-13 16:27:50 -08002238
2239 hdd_for_each_adapter(hdd_ctx, adapter) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002240 switch (adapter->device_mode) {
2241 case QDF_STA_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07002242 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002243 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07002244 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002245 staChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07002246 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002247 qdf_copy_macaddr(&staBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07002248 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002249#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
2250 targetChannel = staChannel;
2251#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
2252 }
2253 break;
2254 case QDF_P2P_CLIENT_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07002255 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002256 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07002257 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002258 p2pChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07002259 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002260 qdf_copy_macaddr(&p2pBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07002261 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002262 p2pMode = "CLI";
2263#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
2264 targetChannel = p2pChannel;
2265#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
2266 }
2267 break;
2268 case QDF_P2P_GO_MODE:
2269 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
2270 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07002271 if (hostapd_state->bss_state == BSS_START
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002272 && hostapd_state->qdf_status ==
2273 QDF_STATUS_SUCCESS) {
Jeff Johnson01206862017-10-27 20:55:59 -07002274 p2pChannel = hdd_ap_ctx->operating_channel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002275 qdf_copy_macaddr(&p2pBssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07002276 &adapter->mac_addr);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002277#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
2278 targetChannel = p2pChannel;
2279#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
2280 }
2281 p2pMode = "GO";
2282 break;
2283 case QDF_SAP_MODE:
2284 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
2285 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07002286 if (hostapd_state->bss_state == BSS_START
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002287 && hostapd_state->qdf_status ==
2288 QDF_STATUS_SUCCESS) {
Jeff Johnson01206862017-10-27 20:55:59 -07002289 apChannel = hdd_ap_ctx->operating_channel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002290 qdf_copy_macaddr(&apBssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07002291 &adapter->mac_addr);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002292#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
2293 targetChannel = apChannel;
2294#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
2295 }
2296 break;
2297 case QDF_IBSS_MODE:
2298 default:
2299 break;
2300 }
2301#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
2302 if (targetChannel) {
2303 /*
2304 * This is first adapter detected as active
2305 * set as default for none concurrency case
2306 */
2307 if (!preAdapterChannel) {
2308 /* If IPA UC data path is enabled,
2309 * target should reserve extra tx descriptors
2310 * for IPA data path.
2311 * Then host data path should allow less TX
2312 * packet pumping in case IPA
2313 * data path enabled
2314 */
2315 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
2316 (QDF_SAP_MODE == adapter->device_mode)) {
2317 adapter->tx_flow_low_watermark =
2318 hdd_ctx->config->TxFlowLowWaterMark +
2319 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
2320 } else {
2321 adapter->tx_flow_low_watermark =
2322 hdd_ctx->config->
2323 TxFlowLowWaterMark;
2324 }
2325 adapter->tx_flow_high_watermark_offset =
2326 hdd_ctx->config->TxFlowHighWaterMarkOffset;
2327 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002328 adapter->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002329 hdd_ctx->config->TxFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07002330 hdd_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002331 adapter->device_mode,
2332 targetChannel,
2333 adapter->tx_flow_low_watermark,
2334 adapter->tx_flow_low_watermark +
2335 adapter->tx_flow_high_watermark_offset,
2336 hdd_ctx->config->TxFlowMaxQueueDepth);
2337 preAdapterChannel = targetChannel;
2338 preAdapterContext = adapter;
2339 } else {
2340 /*
2341 * SCC, disable TX flow control for both
2342 * SCC each adapter cannot reserve dedicated
2343 * channel resource, as a result, if any adapter
2344 * blocked OS Q by flow control,
2345 * blocked adapter will lost chance to recover
2346 */
2347 if (preAdapterChannel == targetChannel) {
2348 /* Current adapter */
2349 adapter->tx_flow_low_watermark = 0;
2350 adapter->
2351 tx_flow_high_watermark_offset = 0;
2352 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002353 adapter->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002354 hdd_ctx->config->
2355 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07002356 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002357 hdd_device_mode_to_string(
2358 adapter->device_mode),
2359 adapter->device_mode,
2360 targetChannel,
2361 adapter->tx_flow_low_watermark,
2362 adapter->tx_flow_low_watermark +
2363 adapter->
2364 tx_flow_high_watermark_offset,
2365 hdd_ctx->config->
2366 TxHbwFlowMaxQueueDepth);
2367
2368 if (!preAdapterContext) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07002369 hdd_err("SCC: Previous adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002370 continue;
2371 }
2372
2373 /* Previous adapter */
2374 preAdapterContext->
2375 tx_flow_low_watermark = 0;
2376 preAdapterContext->
2377 tx_flow_high_watermark_offset = 0;
2378 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002379 preAdapterContext->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002380 hdd_ctx->config->
2381 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07002382 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002383 hdd_device_mode_to_string(
2384 preAdapterContext->device_mode
2385 ),
2386 preAdapterContext->device_mode,
2387 targetChannel,
2388 preAdapterContext->
2389 tx_flow_low_watermark,
2390 preAdapterContext->
2391 tx_flow_low_watermark +
2392 preAdapterContext->
2393 tx_flow_high_watermark_offset,
2394 hdd_ctx->config->
2395 TxHbwFlowMaxQueueDepth);
2396 }
2397 /*
2398 * MCC, each adapter will have dedicated
2399 * resource
2400 */
2401 else {
2402 /* current channel is 2.4 */
2403 if (targetChannel <=
2404 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
2405 channel24 = targetChannel;
2406 channel5 = preAdapterChannel;
2407 adapter2_4 = adapter;
2408 adapter5 = preAdapterContext;
2409 } else {
2410 /* Current channel is 5 */
2411 channel24 = preAdapterChannel;
2412 channel5 = targetChannel;
2413 adapter2_4 = preAdapterContext;
2414 adapter5 = adapter;
2415 }
2416
2417 if (!adapter5) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07002418 hdd_err("MCC: 5GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002419 continue;
2420 }
2421 adapter5->tx_flow_low_watermark =
2422 hdd_ctx->config->
2423 TxHbwFlowLowWaterMark;
2424 adapter5->
2425 tx_flow_high_watermark_offset =
2426 hdd_ctx->config->
2427 TxHbwFlowHighWaterMarkOffset;
2428 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002429 adapter5->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002430 hdd_ctx->config->
2431 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07002432 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002433 hdd_device_mode_to_string(
2434 adapter5->device_mode),
2435 adapter5->device_mode,
2436 channel5,
2437 adapter5->tx_flow_low_watermark,
2438 adapter5->
2439 tx_flow_low_watermark +
2440 adapter5->
2441 tx_flow_high_watermark_offset,
2442 hdd_ctx->config->
2443 TxHbwFlowMaxQueueDepth);
2444
2445 if (!adapter2_4) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07002446 hdd_err("MCC: 2.4GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002447 continue;
2448 }
2449 adapter2_4->tx_flow_low_watermark =
2450 hdd_ctx->config->
2451 TxLbwFlowLowWaterMark;
2452 adapter2_4->
2453 tx_flow_high_watermark_offset =
2454 hdd_ctx->config->
2455 TxLbwFlowHighWaterMarkOffset;
2456 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002457 adapter2_4->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002458 hdd_ctx->config->
2459 TxLbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07002460 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002461 hdd_device_mode_to_string(
2462 adapter2_4->device_mode),
2463 adapter2_4->device_mode,
2464 channel24,
2465 adapter2_4->
2466 tx_flow_low_watermark,
2467 adapter2_4->
2468 tx_flow_low_watermark +
2469 adapter2_4->
2470 tx_flow_high_watermark_offset,
2471 hdd_ctx->config->
2472 TxLbwFlowMaxQueueDepth);
2473
2474 }
2475 }
2476 }
2477 targetChannel = 0;
2478#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002479 }
Dustin Brown920397d2017-12-13 16:27:50 -08002480
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08002481 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
2482}
2483
2484/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002485 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002486 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002487 * @ipa_tx_diff: tx packet count diff from previous tx packet count
2488 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002489 *
2490 * Return: true if IPA is enabled, false otherwise
2491 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002492static void __hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002493 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
2494{
2495 struct hdd_ipa_priv *hdd_ipa;
2496
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002497 *ipa_tx_diff = 0;
2498 *ipa_rx_diff = 0;
2499
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002500 if (wlan_hdd_validate_context(hdd_ctx))
2501 return;
2502
2503 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2504
2505 if (!hdd_ipa_is_enabled(hdd_ctx) ||
2506 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002507 return;
2508 }
2509
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302510 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002511 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
2512 (false == hdd_ipa->resource_loading)) {
2513 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
2514 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002515 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302516 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002517}
2518
2519/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002520 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
2521 * @hdd_ctx: Global HDD context
2522 * @ipa_tx_diff: tx packet count diff from previous tx packet count
2523 * @ipa_rx_diff: rx packet count diff from previous rx packet count
2524 *
2525 * Return: true if IPA is enabled, false otherwise
2526 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002527void hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002528 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
2529{
2530 cds_ssr_protect(__func__);
2531 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
2532 cds_ssr_unprotect(__func__);
2533}
2534
2535/**
2536 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002537 * @adapter: network adapter
2538 * @reason: STAT REQ Reason
2539 *
2540 * Return: None
2541 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07002542static void __hdd_ipa_uc_stat_request(struct hdd_adapter *adapter,
2543 uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002544{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002545 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002546 struct hdd_ipa_priv *hdd_ipa;
2547
Yun Park637d6482016-10-05 10:51:33 -07002548 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002549 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002550
Jeff Johnson399c6272017-08-30 10:51:00 -07002551 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002552
2553 if (wlan_hdd_validate_context(hdd_ctx))
2554 return;
2555
2556 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2557 if (!hdd_ipa_is_enabled(hdd_ctx) ||
2558 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002559 return;
2560 }
2561
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302562 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002563 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
2564 (false == hdd_ipa->resource_loading)) {
2565 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07002566 qdf_mutex_release(&hdd_ipa->ipa_lock);
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07002567 sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07002568 adapter->session_id,
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07002569 WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002570 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07002571 } else {
2572 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002573 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002574}
2575
2576/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002577 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
2578 * @adapter: network adapter
2579 * @reason: STAT REQ Reason
2580 *
2581 * Return: None
2582 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07002583void hdd_ipa_uc_stat_request(struct hdd_adapter *adapter, uint8_t reason)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002584{
2585 cds_ssr_protect(__func__);
2586 __hdd_ipa_uc_stat_request(adapter, reason);
2587 cds_ssr_unprotect(__func__);
2588}
2589
Yun Park637d6482016-10-05 10:51:33 -07002590#ifdef FEATURE_METERING
2591/**
2592 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
2593 * @adapter: network adapter
2594 * @reset_stats: reset stat countis after response
2595 *
2596 * Return: None
2597 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07002598void hdd_ipa_uc_sharing_stats_request(struct hdd_adapter *adapter,
Yun Park637d6482016-10-05 10:51:33 -07002599 uint8_t reset_stats)
2600{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07002601 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07002602 struct hdd_ipa_priv *hdd_ipa;
2603
2604 if (!adapter)
2605 return;
2606
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07002607 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2608 hdd_ipa = hdd_ctx->hdd_ipa;
2609 if (!hdd_ipa_is_enabled(hdd_ctx) ||
2610 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07002611 return;
2612 }
2613
Yun Park637d6482016-10-05 10:51:33 -07002614 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08002615 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07002616 qdf_mutex_release(&hdd_ipa->ipa_lock);
2617 wma_cli_set_command(
Jeff Johnson1b780e42017-10-31 14:11:45 -07002618 (int)adapter->session_id,
Yun Park637d6482016-10-05 10:51:33 -07002619 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
2620 reset_stats, VDEV_CMD);
2621 } else {
2622 qdf_mutex_release(&hdd_ipa->ipa_lock);
2623 }
2624}
2625
2626/**
2627 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
2628 * @adapter: network adapter
2629 * @set_quota: when 1, FW starts quota monitoring
2630 * @quota_bytes: quota limit in bytes
2631 *
2632 * Return: None
2633 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07002634void hdd_ipa_uc_set_quota(struct hdd_adapter *adapter, uint8_t set_quota,
Yun Park637d6482016-10-05 10:51:33 -07002635 uint64_t quota_bytes)
2636{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07002637 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07002638 struct hdd_ipa_priv *hdd_ipa;
2639
2640 if (!adapter)
2641 return;
2642
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07002643 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2644 hdd_ipa = hdd_ctx->hdd_ipa;
2645 if (!hdd_ipa_is_enabled(hdd_ctx) ||
2646 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07002647 return;
2648 }
2649
2650 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
2651 set_quota, quota_bytes);
2652
2653 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08002654 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07002655 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park327e7812017-02-14 15:18:10 -08002656 wma_cli_set2_command(
Jeff Johnson1b780e42017-10-31 14:11:45 -07002657 (int)adapter->session_id,
Yun Park637d6482016-10-05 10:51:33 -07002658 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
Yun Park327e7812017-02-14 15:18:10 -08002659 (set_quota ? quota_bytes&0xffffffff : 0),
2660 (set_quota ? quota_bytes>>32 : 0),
2661 VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07002662 } else {
2663 qdf_mutex_release(&hdd_ipa->ipa_lock);
2664 }
2665}
2666#endif
2667
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002668/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002669 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
2670 * @hdd_ipa: Global HDD IPA context
2671 * @sta_add: Should station be added
2672 * @sta_id: ID of the station being queried
2673 *
2674 * Return: true if the station was found
2675 */
2676static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
2677 bool sta_add, uint8_t sta_id)
2678{
2679 bool sta_found = false;
2680 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07002681
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002682 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2683 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
2684 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
2685 sta_found = true;
2686 break;
2687 }
2688 }
2689 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302690 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002691 "STA ID %d already exist, cannot add", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002692 return sta_found;
2693 }
2694 if (sta_add) {
2695 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2696 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
2697 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
2698 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
2699 return sta_found;
2700 }
2701 }
2702 }
2703 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302704 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002705 "STA ID %d does not exist, cannot delete", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002706 return sta_found;
2707 }
2708 if (!sta_add) {
2709 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2710 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
2711 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
2712 hdd_ipa->assoc_stas_map[idx].is_reserved =
2713 false;
2714 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
2715 return sta_found;
2716 }
2717 }
2718 }
2719 return sta_found;
2720}
2721
2722/**
2723 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
2724 * @hdd_ipa: Global HDD IPA context
2725 *
2726 * Return: 0 on success, negative errno if error
2727 */
2728static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
2729{
Yun Parkfec73dc2017-09-06 10:40:07 -07002730 int result = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07002731 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07002732 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002733
Yun Parke4239802018-01-09 11:01:40 -08002734 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Park199c2ed2017-10-02 11:24:22 -07002735
2736 if (!hdd_ipa->ipa_pipes_down) {
2737 /*
2738 * This shouldn't happen :
2739 * IPA WDI Pipes are already activated
2740 */
2741 WARN_ON(1);
2742 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
2743 "IPA WDI Pipes are already activated");
2744 goto end;
2745 }
Yun Parkfec73dc2017-09-06 10:40:07 -07002746
Yun Parkb4f591d2017-03-29 15:51:01 -07002747 result = cdp_ipa_enable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002748 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302749 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park84c0ceb2018-01-11 10:37:10 -08002750 "Enable IPA WDI PIPE failed: ret=%d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07002751 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002752 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002753
Yun Park777d7242017-03-30 15:38:33 -07002754 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Leo Change3e49442015-10-26 20:07:13 -07002755 hdd_ipa->ipa_pipes_down = false;
Yun Parkb4f591d2017-03-29 15:51:01 -07002756
2757 cdp_ipa_enable_autonomy(soc, (struct cdp_pdev *)pdev);
2758
Yun Parkfec73dc2017-09-06 10:40:07 -07002759end:
Yun Parke4239802018-01-09 11:01:40 -08002760 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07002761 hdd_ipa->ipa_pipes_down);
Yun Park199c2ed2017-10-02 11:24:22 -07002762
Yun Parkfec73dc2017-09-06 10:40:07 -07002763 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002764}
2765
2766/**
2767 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
2768 * @hdd_ipa: Global HDD IPA context
2769 *
2770 * Return: 0 on success, negative errno if error
2771 */
2772static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
2773{
Yun Parkb4f591d2017-03-29 15:51:01 -07002774 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2775 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkfec73dc2017-09-06 10:40:07 -07002776 int result = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002777
Yun Parke4239802018-01-09 11:01:40 -08002778 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Park199c2ed2017-10-02 11:24:22 -07002779
2780 if (hdd_ipa->ipa_pipes_down) {
2781 /*
2782 * This shouldn't happen :
2783 * IPA WDI Pipes are already deactivated
2784 */
2785 WARN_ON(1);
2786 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
2787 "IPA WDI Pipes are already deactivated");
2788 goto end;
2789 }
Leo Change3e49442015-10-26 20:07:13 -07002790
Yun Parkb4f591d2017-03-29 15:51:01 -07002791 cdp_ipa_disable_autonomy(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002792
Yun Parkb4f591d2017-03-29 15:51:01 -07002793 result = cdp_ipa_disable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002794 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302795 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park84c0ceb2018-01-11 10:37:10 -08002796 "Disable IPA WDI PIPE failed: ret=%d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07002797 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002798 }
2799
Yun Parkfec73dc2017-09-06 10:40:07 -07002800 hdd_ipa->ipa_pipes_down = true;
2801
2802end:
Yun Parke4239802018-01-09 11:01:40 -08002803 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07002804 hdd_ipa->ipa_pipes_down);
2805 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002806}
2807
2808/**
2809 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
2810 * @hdd_ipa: Global HDD IPA context
2811 *
2812 * Return: 0 on success, negative errno if error
2813 */
2814static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
2815{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002816 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07002817
Yun Parke4239802018-01-09 11:01:40 -08002818 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07002819
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002820 hdd_ipa->activated_fw_pipe = 0;
2821 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07002822
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002823 /* If RM feature enabled
2824 * Request PROD Resource first
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07002825 * PROD resource may return sync or async manners
2826 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002827 if (hdd_ipa_is_rm_enabled(hdd_ctx)) {
Yun Park84c0ceb2018-01-11 10:37:10 -08002828 if (!hdd_ipa_wdi_rm_request_resource(
2829 hdd_ipa, IPA_RM_RESOURCE_WLAN_PROD)) {
Yun Park4cab6ee2015-10-27 11:43:40 -07002830 /* RM PROD request sync return
2831 * enable pipe immediately
2832 */
2833 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302834 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park84c0ceb2018-01-11 10:37:10 -08002835 "IPA WDI Pipe activation failed");
Yun Park4cab6ee2015-10-27 11:43:40 -07002836 hdd_ipa->resource_loading = false;
2837 return -EBUSY;
2838 }
Sravan Kumar Kairamc76f28a2017-07-25 19:03:40 +05302839 } else {
2840 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park199c2ed2017-10-02 11:24:22 -07002841 "IPA WDI Pipe activation deferred");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002842 }
2843 } else {
2844 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07002845 * Just enabled all the PIPEs
2846 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002847 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302848 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002849 "IPA WDI Pipe activation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002850 hdd_ipa->resource_loading = false;
2851 return -EBUSY;
2852 }
2853 hdd_ipa->resource_loading = false;
2854 }
Yun Park4cab6ee2015-10-27 11:43:40 -07002855
Yun Parke4239802018-01-09 11:01:40 -08002856 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002857 return 0;
2858}
2859
2860/**
2861 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
2862 * @hdd_ipa: Global HDD IPA context
2863 *
2864 * Return: None
2865 */
2866static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
2867{
Leo Changfdb45c32016-10-28 11:09:23 -07002868 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07002869 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002870
Yun Parke4239802018-01-09 11:01:40 -08002871 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07002872
Yun Parkb4f591d2017-03-29 15:51:01 -07002873 if (!pdev) {
Yun Park7c4f31b2016-11-30 10:09:21 -08002874 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2875 QDF_ASSERT(0);
2876 return;
2877 }
2878
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002879 hdd_ipa->resource_unloading = true;
Yun Park777d7242017-03-30 15:38:33 -07002880 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Yun Parkb4f591d2017-03-29 15:51:01 -07002881 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW RX PIPE");
2882 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, false);
Yun Parkfec73dc2017-09-06 10:40:07 -07002883
Yun Parke4239802018-01-09 11:01:40 -08002884 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: IPA WDI Pipes deactivated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002885}
2886
2887/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002888 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
Yun Parkb4f591d2017-03-29 15:51:01 -07002889 * @hdd_ipa: hdd ipa local context
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002890 *
2891 * Will handle IPA UC image loaded indication comes from IPA kernel
2892 *
2893 * Return: None
2894 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002895static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *hdd_ipa)
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002896{
Yun Parkb4f591d2017-03-29 15:51:01 -07002897 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2898 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002899 struct hdd_context *hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07002900 QDF_STATUS status;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002901
Yun Park46255682017-10-09 15:56:34 -07002902 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC READY");
Yun Parkb4f591d2017-03-29 15:51:01 -07002903 if (true == hdd_ipa->uc_loaded) {
Yun Park46255682017-10-09 15:56:34 -07002904 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "UC already loaded");
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002905 return;
2906 }
2907
Yun Parkb4f591d2017-03-29 15:51:01 -07002908 hdd_ctx = hdd_ipa->hdd_ctx;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002909
Yun Parkb4f591d2017-03-29 15:51:01 -07002910 /* Connect pipe */
Yun Park84c0ceb2018-01-11 10:37:10 -08002911 status = hdd_ipa_wdi_setup(hdd_ipa);
Yun Parkb4f591d2017-03-29 15:51:01 -07002912 if (status) {
2913 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2914 "Failure to setup IPA pipes (status=%d)",
2915 status);
2916 return;
2917 }
2918
2919 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002920
2921 /* If already any STA connected, enable IPA/FW PIPEs */
Yun Parkb4f591d2017-03-29 15:51:01 -07002922 if (hdd_ipa->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002923 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002924 "Client already connected, enable IPA/FW PIPEs");
Yun Parkb4f591d2017-03-29 15:51:01 -07002925 hdd_ipa_uc_handle_first_con(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002926 }
2927}
2928
2929/**
Yun Park637d6482016-10-05 10:51:33 -07002930 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2931 * @hdd_ctx: Global HDD context
2932 * @op_msg: operation message received from firmware
2933 *
2934 * Return: QDF_STATUS enumeration
2935 */
2936#ifdef FEATURE_METERING
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002937static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002938 struct op_msg_type *op_msg)
2939{
2940 struct op_msg_type *msg = op_msg;
2941 struct ipa_uc_sharing_stats *uc_sharing_stats;
2942 struct ipa_uc_quota_rsp *uc_quota_rsp;
2943 struct ipa_uc_quota_ind *uc_quota_ind;
2944 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002945 struct hdd_adapter *adapter;
Yun Park637d6482016-10-05 10:51:33 -07002946
2947 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2948
2949 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2950 /* fill-up ipa_uc_sharing_stats structure from FW */
2951 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2952 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2953
2954 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2955 sizeof(struct ipa_uc_sharing_stats));
2956
2957 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2958
2959 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2960 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2961 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2962 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2963 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2964 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2965 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2966 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2967 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2968 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2969 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2970 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2971 /* received set quota response */
2972 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2973 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2974
2975 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2976 sizeof(struct ipa_uc_quota_rsp));
2977
2978 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2979 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2980 "%s: success=%d, quota_bytes=%llu",
2981 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2982 hdd_ipa->ipa_quota_rsp.success,
2983 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2984 hdd_ipa->ipa_quota_rsp.quota_lo);
2985 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2986 /* hit quota limit */
2987 uc_quota_ind = (struct ipa_uc_quota_ind *)
2988 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2989
2990 hdd_ipa->ipa_quota_ind.quota_bytes =
2991 uc_quota_ind->quota_bytes;
2992
2993 /* send quota exceeded indication to IPA */
2994 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2995 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2996 hdd_ipa->ipa_quota_ind.quota_bytes);
2997
2998 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2999 if (adapter)
3000 ipa_broadcast_wdi_quota_reach_ind(
3001 adapter->dev->ifindex,
3002 uc_quota_ind->quota_bytes);
3003 else
3004 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3005 "Failed quota_reach_ind: NULL adapter");
3006 } else {
3007 return QDF_STATUS_E_INVAL;
3008 }
3009
3010 return QDF_STATUS_SUCCESS;
3011}
3012#else
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003013static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07003014 struct op_msg_type *op_msg)
3015{
3016 return QDF_STATUS_E_INVAL;
3017}
3018#endif
3019
Yun Park657c7d72017-06-07 15:44:59 -07003020#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0))
3021/* older versions had a typo */
3022#define num_bam_int_in_non_running_state num_bam_int_in_non_runnning_state
3023#endif
3024
Yun Park637d6482016-10-05 10:51:33 -07003025/**
Yun Park46255682017-10-09 15:56:34 -07003026 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
3027 * @event: IPA WLAN event to be converted to a string
3028 *
3029 * Return: ASCII string representing the IPA WLAN event
3030 */
Yun Park6c86a662017-10-05 16:09:15 -07003031static inline char *hdd_ipa_wlan_event_to_str(qdf_ipa_wlan_event_t event)
Yun Park46255682017-10-09 15:56:34 -07003032{
3033 switch (event) {
3034 CASE_RETURN_STRING(WLAN_CLIENT_CONNECT);
3035 CASE_RETURN_STRING(WLAN_CLIENT_DISCONNECT);
3036 CASE_RETURN_STRING(WLAN_CLIENT_POWER_SAVE_MODE);
3037 CASE_RETURN_STRING(WLAN_CLIENT_NORMAL_MODE);
3038 CASE_RETURN_STRING(SW_ROUTING_ENABLE);
3039 CASE_RETURN_STRING(SW_ROUTING_DISABLE);
3040 CASE_RETURN_STRING(WLAN_AP_CONNECT);
3041 CASE_RETURN_STRING(WLAN_AP_DISCONNECT);
3042 CASE_RETURN_STRING(WLAN_STA_CONNECT);
3043 CASE_RETURN_STRING(WLAN_STA_DISCONNECT);
3044 CASE_RETURN_STRING(WLAN_CLIENT_CONNECT_EX);
3045 default:
3046 return "UNKNOWN";
3047 }
3048}
3049
3050/**
3051 * hdd_ipa_print_session_info - Print IPA session info
3052 * @hdd_ipa: HDD IPA local context
3053 *
3054 * Return: None
3055 */
3056static void hdd_ipa_print_session_info(struct hdd_ipa_priv *hdd_ipa)
3057{
3058 uint8_t session_id;
3059 int device_mode;
3060 struct ipa_uc_pending_event *event = NULL, *next = NULL;
3061 struct hdd_ipa_iface_context *iface_context = NULL;
3062 int i;
3063
3064 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3065 "\n==== IPA SESSION INFO ====\n"
3066 "NUM IFACE: %d\n"
3067 "RM STATE: %d\n"
3068 "ACTIVATED FW PIPE: %d\n"
3069 "SAP NUM STAs: %d\n"
3070 "STA CONNECTED: %d\n"
3071 "CONCURRENT MODE: %s\n"
3072 "RSC LOADING: %d\n"
3073 "RSC UNLOADING: %d\n"
3074 "PENDING CONS REQ: %d\n"
3075 "IPA PIPES DOWN: %d\n"
3076 "IPA UC LOADED: %d\n"
3077 "IPA WDI ENABLED: %d\n"
3078 "NUM SEND MSG: %d\n"
3079 "NUM FREE MSG: %d\n",
3080 hdd_ipa->num_iface,
3081 hdd_ipa->rm_state,
3082 hdd_ipa->activated_fw_pipe,
3083 hdd_ipa->sap_num_connected_sta,
3084 hdd_ipa->sta_connected,
3085 (hdd_ipa->hdd_ctx->mcc_mode ? "MCC" : "SCC"),
3086 hdd_ipa->resource_loading,
3087 hdd_ipa->resource_unloading,
3088 hdd_ipa->pending_cons_req,
3089 hdd_ipa->ipa_pipes_down,
3090 hdd_ipa->uc_loaded,
3091 hdd_ipa->wdi_enabled,
3092 (unsigned int)hdd_ipa->stats.num_send_msg,
3093 (unsigned int)hdd_ipa->stats.num_free_msg);
3094
3095 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3096 iface_context = &hdd_ipa->iface_context[i];
3097 if (!iface_context || !iface_context->adapter)
3098 continue;
3099
Jeff Johnson1b780e42017-10-31 14:11:45 -07003100 session_id = iface_context->adapter->session_id;
Yun Park46255682017-10-09 15:56:34 -07003101 if (session_id >= CSR_ROAM_SESSION_MAX)
3102 continue;
3103
3104 device_mode = iface_context->adapter->device_mode;
3105 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3106 "\nIFACE[%d]: session:%d, sta_id:%d, mode:%s, offload:%d",
3107 i, session_id,
3108 iface_context->sta_id,
3109 hdd_device_mode_to_string(device_mode),
3110 hdd_ipa->vdev_offload_enabled[session_id]);
3111 }
3112
3113 for (i = 0; i < IPA_WLAN_EVENT_MAX; i++)
3114 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3115 "\nEVENT[%d]=%d",
3116 i, hdd_ipa->stats.event[i]);
3117
3118 i = 0;
3119 qdf_list_peek_front(&hdd_ipa->pending_event,
3120 (qdf_list_node_t **)&event);
3121 while (event != NULL) {
3122 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3123 "\nPENDING EVENT[%d]: DEV:%s, EVT:%s, sta_id:%d, MAC:%pM",
3124 i, event->adapter->dev->name,
3125 hdd_ipa_wlan_event_to_str(event->type),
3126 event->sta_id, event->mac_addr);
3127
3128 qdf_list_peek_next(&hdd_ipa->pending_event,
3129 (qdf_list_node_t *)event, (qdf_list_node_t **)&next);
3130 event = next;
3131 next = NULL;
3132 i++;
3133 }
3134}
3135
3136/**
3137 * hdd_ipa_print_txrx_stats - Print HDD IPA TX/RX stats
3138 * @hdd_ipa: HDD IPA local context
3139 *
3140 * Return: None
3141 */
3142static void hdd_ipa_print_txrx_stats(struct hdd_ipa_priv *hdd_ipa)
3143{
3144 int i;
3145 struct hdd_ipa_iface_context *iface_context = NULL;
3146
3147 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3148 "\n==== HDD IPA TX/RX STATS ====\n"
3149 "NUM RM GRANT: %llu\n"
3150 "NUM RM RELEASE: %llu\n"
3151 "NUM RM GRANT IMM: %llu\n"
3152 "NUM CONS PERF REQ: %llu\n"
3153 "NUM PROD PERF REQ: %llu\n"
3154 "NUM RX DROP: %llu\n"
3155 "NUM EXCP PKT: %llu\n"
3156 "NUM TX FWD OK: %llu\n"
3157 "NUM TX FWD ERR: %llu\n"
3158 "NUM TX DESC Q CNT: %llu\n"
3159 "NUM TX DESC ERROR: %llu\n"
3160 "NUM TX COMP CNT: %llu\n"
3161 "NUM TX QUEUED: %llu\n"
3162 "NUM TX DEQUEUED: %llu\n"
3163 "NUM MAX PM QUEUE: %llu\n"
3164 "TX REF CNT: %d\n"
3165 "SUSPENDED: %d\n"
3166 "PEND DESC HEAD: %pK\n"
3167 "TX DESC LIST: %pK\n"
3168 "FREE TX DESC HEAD: %pK\n",
3169 hdd_ipa->stats.num_rm_grant,
3170 hdd_ipa->stats.num_rm_release,
3171 hdd_ipa->stats.num_rm_grant_imm,
3172 hdd_ipa->stats.num_cons_perf_req,
3173 hdd_ipa->stats.num_prod_perf_req,
3174 hdd_ipa->stats.num_rx_drop,
3175 hdd_ipa->stats.num_rx_excep,
3176 hdd_ipa->stats.num_tx_fwd_ok,
3177 hdd_ipa->stats.num_tx_fwd_err,
3178 hdd_ipa->stats.num_tx_desc_q_cnt,
3179 hdd_ipa->stats.num_tx_desc_error,
3180 hdd_ipa->stats.num_tx_comp_cnt,
3181 hdd_ipa->stats.num_tx_queued,
3182 hdd_ipa->stats.num_tx_dequeued,
3183 hdd_ipa->stats.num_max_pm_queue,
3184 hdd_ipa->tx_ref_cnt.counter,
3185 hdd_ipa->suspended,
3186 &hdd_ipa->pend_desc_head,
3187 hdd_ipa->tx_desc_list,
3188 &hdd_ipa->free_tx_desc_head);
3189
3190 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3191 iface_context = &hdd_ipa->iface_context[i];
3192 if (!iface_context || !iface_context->adapter)
3193 continue;
3194
3195 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3196 "IFACE[%d]: TX:%llu, TX DROP:%llu, TX ERR:%llu, TX CAC DROP:%llu, RX IPA EXCEP:%llu",
3197 i,
3198 iface_context->stats.num_tx,
3199 iface_context->stats.num_tx_drop,
3200 iface_context->stats.num_tx_err,
3201 iface_context->stats.num_tx_cac_drop,
3202 iface_context->stats.num_rx_ipa_excep);
3203 }
3204}
3205
3206/**
3207 * hdd_ipa_print_fw_wdi_stats - Print WLAN FW WDI stats
3208 * @hdd_ipa: HDD IPA local context
3209 *
3210 * Return: None
3211 */
3212static void hdd_ipa_print_fw_wdi_stats(struct hdd_ipa_priv *hdd_ipa,
3213 struct ipa_uc_fw_stats *uc_fw_stat)
3214{
3215 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3216 "\n==== WLAN FW WDI TX STATS ====\n"
3217 "COMP RING BASE: 0x%x\n"
3218 "COMP RING SIZE: %d\n"
3219 "COMP RING DBELL : 0x%x\n"
3220 "COMP RING DBELL IND VAL : %d\n"
3221 "COMP RING DBELL CACHED VAL : %d\n"
3222 "PKTS ENQ : %d\n"
3223 "PKTS COMP : %d\n"
3224 "IS SUSPEND : %d\n",
3225 uc_fw_stat->tx_comp_ring_base,
3226 uc_fw_stat->tx_comp_ring_size,
3227 uc_fw_stat->tx_comp_ring_dbell_addr,
3228 uc_fw_stat->tx_comp_ring_dbell_ind_val,
3229 uc_fw_stat->tx_comp_ring_dbell_cached_val,
3230 uc_fw_stat->tx_pkts_enqueued,
3231 uc_fw_stat->tx_pkts_completed,
3232 uc_fw_stat->tx_is_suspend);
3233
3234 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3235 "\n==== WLAN FW WDI RX STATS ====\n"
3236 "IND RING BASE: 0x%x\n"
3237 "IND RING SIZE: %d\n"
3238 "IND RING DBELL : 0x%x\n"
3239 "IND RING DBELL IND VAL : %d\n"
3240 "IND RING DBELL CACHED VAL : %d\n"
3241 "RDY IND ADDR : 0x%x\n"
3242 "RDY IND CACHE VAL : %d\n"
3243 "RFIL IND : %d\n"
3244 "NUM PKT INDICAT : %d\n"
3245 "BUF REFIL : %d\n"
3246 "NUM DROP NO SPC : %d\n"
3247 "NUM DROP NO BUF : %d\n"
3248 "IS SUSPND : %d\n",
3249 uc_fw_stat->rx_ind_ring_base,
3250 uc_fw_stat->rx_ind_ring_size,
3251 uc_fw_stat->rx_ind_ring_dbell_addr,
3252 uc_fw_stat->rx_ind_ring_dbell_ind_val,
3253 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
3254 uc_fw_stat->rx_ind_ring_rdidx_addr,
3255 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
3256 uc_fw_stat->rx_refill_idx,
3257 uc_fw_stat->rx_num_pkts_indicated,
3258 uc_fw_stat->rx_buf_refilled,
3259 uc_fw_stat->rx_num_ind_drop_no_space,
3260 uc_fw_stat->rx_num_ind_drop_no_buf,
3261 uc_fw_stat->rx_is_suspend);
3262}
3263
3264/**
3265 * hdd_ipa_print_ipa_wdi_stats - Print IPA WDI stats
3266 * @hdd_ipa: HDD IPA local context
3267 *
3268 * Return: None
3269 */
3270static void hdd_ipa_print_ipa_wdi_stats(struct hdd_ipa_priv *hdd_ipa)
3271{
3272 struct IpaHwStatsWDIInfoData_t ipa_stat;
3273
3274 ipa_get_wdi_stats(&ipa_stat);
3275
3276 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3277 "\n==== IPA WDI TX STATS ====\n"
3278 "NUM PROCD : %d\n"
3279 "CE DBELL : 0x%x\n"
3280 "NUM DBELL FIRED : %d\n"
3281 "COMP RNG FULL : %d\n"
3282 "COMP RNG EMPT : %d\n"
3283 "COMP RNG USE HGH : %d\n"
3284 "COMP RNG USE LOW : %d\n"
3285 "BAM FIFO FULL : %d\n"
3286 "BAM FIFO EMPT : %d\n"
3287 "BAM FIFO USE HGH : %d\n"
3288 "BAM FIFO USE LOW : %d\n"
3289 "NUM DBELL : %d\n"
3290 "NUM UNEXP DBELL : %d\n"
3291 "NUM BAM INT HDL : 0x%x\n"
3292 "NUM BAM INT NON-RUN : 0x%x\n"
3293 "NUM QMB INT HDL : 0x%x\n",
3294 ipa_stat.tx_ch_stats.num_pkts_processed,
3295 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
3296 ipa_stat.tx_ch_stats.num_db_fired,
3297 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
3298 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
3299 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
3300 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
3301 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
3302 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
3303 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
3304 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
3305 ipa_stat.tx_ch_stats.num_db,
3306 ipa_stat.tx_ch_stats.num_unexpected_db,
3307 ipa_stat.tx_ch_stats.num_bam_int_handled,
3308 ipa_stat.tx_ch_stats.
3309#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
3310 num_bam_int_in_non_running_state,
3311#else
3312 num_bam_int_in_non_runnning_state,
3313#endif
3314 ipa_stat.tx_ch_stats.num_qmb_int_handled);
3315
3316 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
3317 "\n==== IPA WDI RX STATS ====\n"
3318 "MAX OST PKT : %d\n"
3319 "NUM PKT PRCSD : %d\n"
3320 "RNG RP : 0x%x\n"
3321 "IND RNG FULL : %d\n"
3322 "IND RNG EMPT : %d\n"
3323 "IND RNG USE HGH : %d\n"
3324 "IND RNG USE LOW : %d\n"
3325 "BAM FIFO FULL : %d\n"
3326 "BAM FIFO EMPT : %d\n"
3327 "BAM FIFO USE HGH : %d\n"
3328 "BAM FIFO USE LOW : %d\n"
3329 "NUM DB : %d\n"
3330 "NUM UNEXP DB : %d\n"
3331 "NUM BAM INT HNDL : 0x%x\n",
3332 ipa_stat.rx_ch_stats.max_outstanding_pkts,
3333 ipa_stat.rx_ch_stats.num_pkts_processed,
3334 ipa_stat.rx_ch_stats.rx_ring_rp_value,
3335 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
3336 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
3337 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
3338 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
3339 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
3340 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
3341 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
3342 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
3343 ipa_stat.rx_ch_stats.num_db,
3344 ipa_stat.rx_ch_stats.num_unexpected_db,
3345 ipa_stat.rx_ch_stats.num_bam_int_handled);
3346}
3347
3348/**
3349 * hdd_ipa_uc_info() - Print IPA uC resource and session information
3350 * @adapter: network adapter
3351 *
3352 * Return: None
3353 */
3354void hdd_ipa_uc_info(struct hdd_context *hdd_ctx)
3355{
3356 struct hdd_ipa_priv *hdd_ipa;
3357
3358 hdd_ipa = hdd_ctx->hdd_ipa;
3359
3360 if (!hdd_ipa) {
3361 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3362 "HDD IPA context is NULL");
3363 return;
3364 }
3365
3366 /* IPA session info */
3367 hdd_ipa_print_session_info(hdd_ipa);
3368}
3369
3370/**
3371 * hdd_ipa_uc_stat() - Print IPA uC stats
3372 * @adapter: network adapter
3373 *
3374 * Return: None
3375 */
3376void hdd_ipa_uc_stat(struct hdd_adapter *adapter)
3377{
3378 struct hdd_context *hdd_ctx;
3379 struct hdd_ipa_priv *hdd_ipa;
3380
3381 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3382 hdd_ipa = hdd_ctx->hdd_ipa;
3383
3384 if (!hdd_ipa) {
3385 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3386 "HDD IPA context is NULL");
3387 return;
3388 }
3389
3390 /* HDD IPA TX/RX stats */
3391 hdd_ipa_print_txrx_stats(hdd_ipa);
3392 /* IPA WDI stats */
3393 hdd_ipa_print_ipa_wdi_stats(hdd_ipa);
3394 /* WLAN FW WDI stats */
3395 hdd_ipa_uc_stat_request(adapter, HDD_IPA_UC_STAT_REASON_DEBUG);
3396}
3397
3398/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003399 * hdd_ipa_uc_op_cb() - IPA uC operation callback
3400 * @op_msg: operation message received from firmware
3401 * @usr_ctxt: user context registered with TL (we register the HDD Global
3402 * context)
3403 *
3404 * Return: None
3405 */
3406static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
3407{
3408 struct op_msg_type *msg = op_msg;
3409 struct ipa_uc_fw_stats *uc_fw_stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003410 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003411 struct hdd_context *hdd_ctx;
Yun Parka658cf92018-01-24 17:19:29 -08003412 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3413 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303414 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003415
Alok Kumareff0d772018-02-09 16:01:06 +05303416 if (!pdev) {
3417 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
3418 return;
3419 }
3420
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421 if (!op_msg || !usr_ctxt) {
Yun Park46255682017-10-09 15:56:34 -07003422 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "INVALID ARG");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423 return;
3424 }
3425
3426 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303427 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07003428 "INVALID OPCODE %d", msg->op_code);
jiadd91a6842017-08-01 14:46:02 +08003429 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003430 return;
3431 }
3432
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003433 hdd_ctx = (struct hdd_context *) usr_ctxt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003434
3435 /*
3436 * When SSR is going on or driver is unloading, just return.
3437 */
3438 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303439 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303440 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003441 return;
3442 }
3443
3444 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
3445
Govind Singhb6a89772016-08-12 11:23:35 +05303446 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08003447 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003448
3449 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
3450 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303451 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452 hdd_ipa->activated_fw_pipe++;
3453 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
3454 hdd_ipa->resource_loading = false;
Yun Park777d7242017-03-30 15:38:33 -07003455 complete(&hdd_ipa->ipa_resource_comp);
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003456 if (hdd_ipa->wdi_enabled == false) {
3457 hdd_ipa->wdi_enabled = true;
3458 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
3459 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
3460 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003461 }
Yun Parka4bb37c2017-12-08 16:14:22 -08003462 hdd_ipa_uc_proc_pending_event(hdd_ipa, true);
Yun Parkccc6d7a2015-12-02 14:50:13 -08003463 if (hdd_ipa->pending_cons_req)
Yun Park84c0ceb2018-01-11 10:37:10 -08003464 hdd_ipa_wdi_rm_notify_completion(
Yun Parkccc6d7a2015-12-02 14:50:13 -08003465 IPA_RM_RESOURCE_GRANTED,
3466 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08003467 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003468 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303469 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07003470 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Yun Parka658cf92018-01-24 17:19:29 -08003471 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303472 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parka658cf92018-01-24 17:19:29 -08003473
3474 if (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code) {
3475 hdd_ipa_uc_disable_pipes(hdd_ipa);
3476 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
3477 "Disable FW TX PIPE");
3478 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev,
3479 false, true);
3480 }
3481
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003482 hdd_ipa->activated_fw_pipe--;
3483 if (!hdd_ipa->activated_fw_pipe) {
Yun Park777d7242017-03-30 15:38:33 -07003484 /*
3485 * Async return success from FW
3486 * Disable/suspend all the PIPEs
3487 */
Yun Parka4bb37c2017-12-08 16:14:22 -08003488 hdd_ipa->resource_unloading = false;
3489 complete(&hdd_ipa->ipa_resource_comp);
Yun Park5b635012015-12-02 15:05:01 -08003490 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
Yun Park84c0ceb2018-01-11 10:37:10 -08003491 hdd_ipa_wdi_rm_release_resource(
3492 hdd_ipa, IPA_RM_RESOURCE_WLAN_PROD);
Yun Parka4bb37c2017-12-08 16:14:22 -08003493 hdd_ipa_uc_proc_pending_event(hdd_ipa, false);
Yun Park5b635012015-12-02 15:05:01 -08003494 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003495 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303496 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07003497 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003498 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003499 uc_fw_stat = (struct ipa_uc_fw_stats *)
Yun Park46255682017-10-09 15:56:34 -07003500 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003501
Yun Park46255682017-10-09 15:56:34 -07003502 /* WLAN FW WDI stats */
3503 hdd_ipa_print_fw_wdi_stats(hdd_ipa, uc_fw_stat);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003504 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
3505 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
3506 /* STATs from FW */
3507 uc_fw_stat = (struct ipa_uc_fw_stats *)
3508 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303509 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003510 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
3511 uc_fw_stat->tx_pkts_completed,
3512 hdd_ipa->ipa_p_tx_packets);
3513 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
3514 (uc_fw_stat->rx_num_ind_drop_no_space +
3515 uc_fw_stat->rx_num_ind_drop_no_buf +
3516 uc_fw_stat->rx_num_pkts_indicated),
3517 hdd_ipa->ipa_p_rx_packets);
3518
3519 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
3520 hdd_ipa->ipa_p_rx_packets =
3521 (uc_fw_stat->rx_num_ind_drop_no_space +
3522 uc_fw_stat->rx_num_ind_drop_no_buf +
3523 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303524 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003525 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
3526 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
3527 hdd_ipa_uc_loaded_handler(hdd_ipa);
3528 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07003529 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
3530 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
3531 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003532 }
Yun Park8957d802017-01-25 12:27:29 -08003533
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303534 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003535}
3536
3537
3538/**
3539 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
3540 * @adapter: device adapter instance
3541 * @offload_type: MCC or SCC
3542 * @enable: TX offload enable or disable
3543 *
3544 * Return: none
3545 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003546static void hdd_ipa_uc_offload_enable_disable(struct hdd_adapter *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003547 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003548{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003549 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003550 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07003551 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003552 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003553
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003554 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003555 return;
3556
Yun Park8292dcb2016-10-07 16:46:06 -07003557 iface_context = adapter->ipa_context;
Jeff Johnson1b780e42017-10-31 14:11:45 -07003558 session_id = adapter->session_id;
Yun Park8292dcb2016-10-07 16:46:06 -07003559
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003560 if (!iface_context) {
3561 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3562 "Interface context is NULL");
3563 return;
3564 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08003565 if (session_id >= CSR_ROAM_SESSION_MAX) {
3566 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3567 "invalid session id: %d", session_id);
3568 return;
3569 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003570 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park199c2ed2017-10-02 11:24:22 -07003571 /*
3572 * This shouldn't happen :
3573 * IPA offload status is already set as desired
3574 */
3575 WARN_ON(1);
3576 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
Yun Parkb4f591d2017-03-29 15:51:01 -07003577 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003578 "IPA offload status is already set",
3579 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07003580 return;
3581 }
3582
Jeff Johnson1b780e42017-10-31 14:11:45 -07003583 if (wlan_hdd_validate_session_id(adapter->session_id)) {
Yun Park4540e862016-11-10 16:30:06 -08003584 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3585 "invalid session id: %d, offload_type=%d, enable=%d",
Jeff Johnson1b780e42017-10-31 14:11:45 -07003586 adapter->session_id, offload_type, enable);
Yun Park4540e862016-11-10 16:30:06 -08003587 return;
3588 }
3589
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303590 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003591 sizeof(ipa_offload_enable_disable));
3592 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003593 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003594 ipa_offload_enable_disable.enable = enable;
3595
Yun Park199c2ed2017-10-02 11:24:22 -07003596 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07003597 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003598 ipa_offload_enable_disable.offload_type,
3599 ipa_offload_enable_disable.vdev_id,
3600 ipa_offload_enable_disable.enable);
3601
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303602 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003603 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07003604 adapter->session_id, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303605 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07003606 "Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
3607 ipa_offload_enable_disable.offload_type,
3608 ipa_offload_enable_disable.vdev_id,
3609 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07003610 } else {
3611 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08003612 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07003613 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003614 }
3615}
3616
3617/**
3618 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
3619 * @work: uC OP work
3620 *
3621 * Return: None
3622 */
3623static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
3624{
3625 struct op_msg_type *msg;
3626 struct uc_op_work_struct *uc_op_work = container_of(work,
3627 struct uc_op_work_struct, work);
3628 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3629
3630 cds_ssr_protect(__func__);
3631
3632 msg = uc_op_work->msg;
3633 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08003634 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07003635 "posted msg %d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636
3637 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
3638
3639 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003640}
3641
3642/**
3643 * hdd_ipa_uc_op_event_handler() - Adapter lookup
3644 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
3645 * @op_msg: operation message received from firmware
3646 * @hdd_ctx: Global HDD context
3647 *
3648 * Return: None
3649 */
3650static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
3651{
3652 struct hdd_ipa_priv *hdd_ipa;
3653 struct op_msg_type *msg;
3654 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303655 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003656
3657 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303658 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003659 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003660
3661 msg = (struct op_msg_type *)op_msg;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003662 hdd_ipa = ((struct hdd_context *)hdd_ctx)->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003663
3664 if (unlikely(!hdd_ipa))
3665 goto end;
3666
3667 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Yun Parkb4f591d2017-03-29 15:51:01 -07003668 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid OP Code (%d)",
3669 msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003670 goto end;
3671 }
3672
3673 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
3674 if (uc_op_work->msg)
3675 /* When the same uC OPCODE is already pended, just return */
3676 goto end;
3677
3678 uc_op_work->msg = msg;
3679 schedule_work(&uc_op_work->work);
3680 return;
3681
3682end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303683 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684}
3685
3686/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003687 * hdd_ipa_init_uc_op_work - init ipa uc op work
3688 * @work: struct work_struct
3689 * @work_handler: work_handler
3690 *
3691 * Return: none
3692 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003693static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07003694 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08003695{
3696 INIT_WORK(work, work_handler);
3697}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003698
Rajeev Kumar217f2172016-01-06 18:11:55 -08003699/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003700 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
3701 * @hdd_ctx: Global HDD context
3702 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003703 * This function is called to update IPA pipe configuration with resources
3704 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
3705 * (cds_enable)
3706 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303707 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003709QDF_STATUS hdd_ipa_uc_ol_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003710{
Yun Parkb4f591d2017-03-29 15:51:01 -07003711 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07003712 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08003713 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkb4f591d2017-03-29 15:51:01 -07003714 uint8_t i;
3715 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003716
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003717 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3718 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003719
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08003720 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003721
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003722 /* Do only IPA Pipe specific configuration here. All one time
3723 * initialization wrt IPA UC shall in hdd_ipa_init and those need
3724 * to be reinit at SSR shall in be SSR deinit / reinit functions.
3725 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003726 if (!pdev || !soc) {
3727 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkb4f591d2017-03-29 15:51:01 -07003728 status = QDF_STATUS_E_FAILURE;
Yun Parkbaa62862017-01-18 13:43:34 -08003729 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003730 }
Yun Parka4bb37c2017-12-08 16:14:22 -08003731
3732 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3733 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3734 hdd_ipa->vdev_offload_enabled[i] = false;
3735 }
3736
Yun Parkb4f591d2017-03-29 15:51:01 -07003737 if (cdp_ipa_get_resource(soc, (struct cdp_pdev *)pdev)) {
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003738 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
3739 "IPA UC resource alloc fail");
Yun Park199c2ed2017-10-02 11:24:22 -07003740 status = QDF_STATUS_E_FAILURE;
3741 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003742 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003743
Yun Parkb4f591d2017-03-29 15:51:01 -07003744 if (true == hdd_ipa->uc_loaded) {
Yun Park84c0ceb2018-01-11 10:37:10 -08003745 status = hdd_ipa_wdi_setup(hdd_ipa);
Yun Parkb4f591d2017-03-29 15:51:01 -07003746 if (status) {
Yun Parkbaa62862017-01-18 13:43:34 -08003747 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07003748 "Failure to setup IPA pipes (status=%d)",
3749 status);
Yun Park199c2ed2017-10-02 11:24:22 -07003750 status = QDF_STATUS_E_FAILURE;
3751 goto fail_return;
Yun Parkbaa62862017-01-18 13:43:34 -08003752 }
Yun Park637d6482016-10-05 10:51:33 -07003753
Yun Parkb4f591d2017-03-29 15:51:01 -07003754 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
3755 hdd_ipa_init_metering(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003756 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003757
Yun Parkb4f591d2017-03-29 15:51:01 -07003758 cdp_ipa_register_op_cb(soc, (struct cdp_pdev *)pdev,
Yun Parkbaa62862017-01-18 13:43:34 -08003759 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
3760
Yun Parkb4f591d2017-03-29 15:51:01 -07003761 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
3762 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
Yun Parka4bb37c2017-12-08 16:14:22 -08003763 hdd_ipa_uc_fw_op_event_handler);
Yun Parkb4f591d2017-03-29 15:51:01 -07003764 hdd_ipa->uc_op_work[i].msg = NULL;
3765 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003766
Yun Parkbaa62862017-01-18 13:43:34 -08003767fail_return:
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08003768 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: status=%d", status);
Yun Parkb4f591d2017-03-29 15:51:01 -07003769 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003770}
3771
Leo Change3e49442015-10-26 20:07:13 -07003772/**
Yun Parkd8fb1a82017-10-13 16:48:20 -07003773 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
3774 * @hdd_ipa: pointer to HDD IPA struct
3775 *
3776 * Return: none
3777 */
3778static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
3779{
3780 struct ipa_uc_pending_event *pending_event = NULL;
3781
3782 while (qdf_list_remove_front(&hdd_ipa->pending_event,
3783 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
3784 qdf_mem_free(pending_event);
3785}
3786
3787/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303788 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
3789 * @hdd_ctx: Global HDD context
3790 *
3791 * Return: 0 on success, negativer errno on error
3792 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003793int hdd_ipa_uc_ol_deinit(struct hdd_context *hdd_ctx)
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303794{
3795 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
Yun Park6edb2172018-01-14 00:18:05 -08003796 int i, ret = 0;
Yun Parkb4f591d2017-03-29 15:51:01 -07003797 QDF_STATUS status;
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303798
Yun Parke4239802018-01-09 11:01:40 -08003799 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003800
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303801 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3802 return ret;
3803
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05303804 if (!hdd_ipa->ipa_pipes_down)
3805 hdd_ipa_uc_disable_pipes(hdd_ipa);
3806
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303807 if (true == hdd_ipa->uc_loaded) {
Yun Parkb4f591d2017-03-29 15:51:01 -07003808 status = cdp_ipa_cleanup(cds_get_context(QDF_MODULE_ID_SOC),
3809 hdd_ipa->tx_pipe_handle,
3810 hdd_ipa->rx_pipe_handle);
3811 if (status) {
3812 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3813 "Failure to cleanup IPA pipes (status=%d)",
3814 status);
Yun Park6edb2172018-01-14 00:18:05 -08003815 ret = -EFAULT;
Yun Parkb4f591d2017-03-29 15:51:01 -07003816 }
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303817 }
3818
Yun Parka4bb37c2017-12-08 16:14:22 -08003819 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07003820 hdd_ipa_cleanup_pending_event(hdd_ipa);
Yun Parka4bb37c2017-12-08 16:14:22 -08003821 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07003822
Yun Park6edb2172018-01-14 00:18:05 -08003823 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
3824 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
3825 qdf_mem_free(hdd_ipa->uc_op_work[i].msg);
3826 hdd_ipa->uc_op_work[i].msg = NULL;
3827 }
3828
Yun Parke4239802018-01-09 11:01:40 -08003829 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: ret=%d", ret);
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303830 return ret;
3831}
3832
3833/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003834 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07003835 * @hdd_ctx: hdd main context
3836 *
3837 * Force shutdown IPA pipe
3838 * Independent of FW pipe status, IPA pipe shutdonw progress
3839 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3840 * independent from FW pipe status
3841 *
3842 * Return: NONE
3843 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003844static void __hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07003845{
3846 struct hdd_ipa_priv *hdd_ipa;
3847
Yun Parke4239802018-01-09 11:01:40 -08003848 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003849
Leo Change3e49442015-10-26 20:07:13 -07003850 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
3851 return;
3852
3853 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
3854 if (false == hdd_ipa->ipa_pipes_down) {
Yun Park46255682017-10-09 15:56:34 -07003855 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Parkb4f591d2017-03-29 15:51:01 -07003856 "IPA pipes are not down yet, force shutdown");
Leo Change3e49442015-10-26 20:07:13 -07003857 hdd_ipa_uc_disable_pipes(hdd_ipa);
3858 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003859 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb4f591d2017-03-29 15:51:01 -07003860 "IPA pipes are down, do nothing");
Leo Change3e49442015-10-26 20:07:13 -07003861 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003862
Yun Parke4239802018-01-09 11:01:40 -08003863 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Leo Change3e49442015-10-26 20:07:13 -07003864}
3865
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003866/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003867 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
3868 * __hdd_ipa_uc_force_pipe_shutdown
3869 * @hdd_ctx: hdd main context
3870 *
3871 * Force shutdown IPA pipe
3872 * Independent of FW pipe status, IPA pipe shutdonw progress
3873 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3874 * independent from FW pipe status
3875 *
3876 * Return: NONE
3877 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003878void hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003879{
3880 cds_ssr_protect(__func__);
3881 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
3882 cds_ssr_unprotect(__func__);
3883}
3884
3885/**
Govind Singh9c58eba2016-09-02 16:23:06 +05303886 * hdd_ipa_msg_free_fn() - Free an IPA message
3887 * @buff: pointer to the IPA message
3888 * @len: length of the IPA message
3889 * @type: type of IPA message
3890 *
3891 * Return: None
3892 */
3893static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
3894{
Srinivas Girigowda97852372017-03-06 16:52:59 -08003895 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05303896 ghdd_ipa->stats.num_free_msg++;
3897 qdf_mem_free(buff);
3898}
3899
Govind Singh9c58eba2016-09-02 16:23:06 +05303900/**
jge62037862016-12-09 10:44:33 +08003901 * hdd_ipa_uc_send_evt() - send event to ipa
3902 * @hdd_ctx: pointer to hdd context
3903 * @type: event type
3904 * @mac_addr: pointer to mac address
3905 *
3906 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303907 *
3908 * Return: 0 - Success
3909 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003910static int hdd_ipa_uc_send_evt(struct hdd_adapter *adapter,
Yun Park6c86a662017-10-05 16:09:15 -07003911 qdf_ipa_wlan_event_t type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303912{
jge62037862016-12-09 10:44:33 +08003913 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07003914 qdf_ipa_msg_meta_t meta;
3915 qdf_ipa_wlan_msg_t *msg;
Govind Singh9c58eba2016-09-02 16:23:06 +05303916 int ret = 0;
jge62037862016-12-09 10:44:33 +08003917
Yun Park6c86a662017-10-05 16:09:15 -07003918 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
3919 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
jge62037862016-12-09 10:44:33 +08003920 if (msg == NULL) {
3921 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3922 "msg allocation failed");
3923 return -ENOMEM;
3924 }
3925
Yun Park6c86a662017-10-05 16:09:15 -07003926 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
3927 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), adapter->dev->name,
jge62037862016-12-09 10:44:33 +08003928 IPA_RESOURCE_NAME_MAX);
Yun Park6c86a662017-10-05 16:09:15 -07003929 memcpy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, ETH_ALEN);
Yun Park199c2ed2017-10-02 11:24:22 -07003930 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Yun Park6c86a662017-10-05 16:09:15 -07003931 QDF_IPA_WLAN_MSG_NAME(msg), QDF_IPA_MSG_META_MSG_TYPE(&meta));
3932 ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
jge62037862016-12-09 10:44:33 +08003933 if (ret) {
3934 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3935 "%s: Evt: %d fail:%d",
Yun Park6c86a662017-10-05 16:09:15 -07003936 QDF_IPA_WLAN_MSG_NAME(msg),
3937 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
jge62037862016-12-09 10:44:33 +08003938 qdf_mem_free(msg);
3939 return ret;
3940 }
3941
3942 hdd_ipa->stats.num_send_msg++;
3943
3944 return ret;
3945}
3946
3947/**
3948 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3949 * @hdd_ctx: pointer to hdd adapter
3950 *
3951 * Send disconnect client event to IPA driver during SSR
3952 *
3953 * Return: 0 - Success
3954 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003955static int hdd_ipa_uc_disconnect_client(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003956{
3957 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3958 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303959 int i;
3960
Yun Parke4239802018-01-09 11:01:40 -08003961 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Govind Singh9c58eba2016-09-02 16:23:06 +05303962 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003963 if (qdf_is_macaddr_broadcast(&adapter->sta_info[i].sta_mac))
Govind Singh9c58eba2016-09-02 16:23:06 +05303964 continue;
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003965 if ((adapter->sta_info[i].in_use) &&
3966 (!adapter->sta_info[i].is_deauth_in_progress) &&
jge62037862016-12-09 10:44:33 +08003967 hdd_ipa->sap_num_connected_sta) {
3968 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003969 adapter->sta_info[i].sta_mac.bytes);
jge62037862016-12-09 10:44:33 +08003970 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303971 }
3972 }
Yun Parke4239802018-01-09 11:01:40 -08003973 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07003974 hdd_ipa->sap_num_connected_sta);
Govind Singh9c58eba2016-09-02 16:23:06 +05303975
3976 return ret;
3977}
3978
3979/**
jge62037862016-12-09 10:44:33 +08003980 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3981 * @hdd_ctx: pointer to hdd adapter
3982 *
3983 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303984 *
3985 * Return: 0 - Success
3986 */
jge62037862016-12-09 10:44:33 +08003987
Jeff Johnson49d45e62017-08-29 14:30:42 -07003988static int hdd_ipa_uc_disconnect_ap(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003989{
3990 int ret = 0;
3991
Yun Parke4239802018-01-09 11:01:40 -08003992 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003993 if (adapter->ipa_context) {
jge62037862016-12-09 10:44:33 +08003994 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3995 adapter->dev->dev_addr);
Yun Parkfec73dc2017-09-06 10:40:07 -07003996 }
Yun Parke4239802018-01-09 11:01:40 -08003997 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
jge62037862016-12-09 10:44:33 +08003998
3999 return ret;
4000}
4001
jge62037862016-12-09 10:44:33 +08004002/**
4003 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
4004 * @hdd_ctx: pointer to hdd adapter
4005 *
4006 * Send disconnect sta event to IPA driver during SSR
4007 *
4008 * Return: 0 - Success
4009 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07004010static int hdd_ipa_uc_disconnect_sta(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08004011{
Jeff Johnsond377dce2017-10-04 10:32:42 -07004012 struct hdd_station_ctx *sta_ctx;
jge62037862016-12-09 10:44:33 +08004013 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4014 int ret = 0;
4015
Yun Parke4239802018-01-09 11:01:40 -08004016 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08004017 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08004018 hdd_ipa->sta_connected) {
Jeff Johnsond377dce2017-10-04 10:32:42 -07004019 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
jge62037862016-12-09 10:44:33 +08004020 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004021 sta_ctx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08004022 }
Yun Parke4239802018-01-09 11:01:40 -08004023 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
jge62037862016-12-09 10:44:33 +08004024
4025 return ret;
4026}
jge62037862016-12-09 10:44:33 +08004027
4028/**
4029 * hdd_ipa_uc_disconnect() - send disconnect ipa event
4030 * @hdd_ctx: pointer to hdd context
4031 *
4032 * Send disconnect event to IPA driver during SSR
4033 *
4034 * Return: 0 - Success
4035 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004036static int hdd_ipa_uc_disconnect(struct hdd_context *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05304037{
Jeff Johnson49d45e62017-08-29 14:30:42 -07004038 struct hdd_adapter *adapter;
Govind Singh9c58eba2016-09-02 16:23:06 +05304039 int ret = 0;
4040
Dustin Brown920397d2017-12-13 16:27:50 -08004041 hdd_for_each_adapter(hdd_ctx, adapter) {
jge62037862016-12-09 10:44:33 +08004042 if (adapter->device_mode == QDF_SAP_MODE) {
4043 hdd_ipa_uc_disconnect_client(adapter);
4044 hdd_ipa_uc_disconnect_ap(adapter);
4045 } else if (adapter->device_mode == QDF_STA_MODE) {
4046 hdd_ipa_uc_disconnect_sta(adapter);
4047 }
Govind Singh9c58eba2016-09-02 16:23:06 +05304048 }
4049
4050 return ret;
4051}
4052
4053/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004054 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004055 *
4056 * Deinit basic IPA UC host side to be in sync reloaded FW during
4057 * SSR
4058 *
4059 * Return: 0 - Success
4060 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004061static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004062{
4063 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4064 int idx;
4065 struct hdd_ipa_iface_context *iface_context;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004066 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004067
Yun Parke4239802018-01-09 11:01:40 -08004068 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07004069
Arun Khandavallicc544b32017-01-30 19:52:16 +05304070 if (!hdd_ipa)
4071 return 0;
4072
4073 hdd_ctx = hdd_ipa->hdd_ctx;
4074 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004075 return 0;
4076
jge62037862016-12-09 10:44:33 +08004077 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05304078 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08004079
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004080 /* Clean up HDD IPA interfaces */
4081 for (idx = 0; (hdd_ipa->num_iface > 0) &&
4082 (idx < HDD_IPA_MAX_IFACE); idx++) {
4083 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08004084 if (iface_context->adapter && iface_context->adapter->magic ==
4085 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004086 hdd_ipa_cleanup_iface(iface_context);
4087 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08004088 hdd_ipa->num_iface = 0;
Yun Parka4bb37c2017-12-08 16:14:22 -08004089
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004090 /* After SSR, wlan driver reloads FW again. But we need to protect
4091 * IPA submodule during SSR transient state. So deinit basic IPA
4092 * UC host side to be in sync with reloaded FW during SSR
4093 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004094
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304095 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004096 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
4097 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
4098 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
4099 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304100 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004101
Guolei Bianca144d82016-11-10 11:07:42 +08004102 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
4103 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
4104
Manikandan Mohan2e803a02017-02-14 14:57:53 -08004105 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
4106 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
4107 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
4108 hdd_ipa->uc_op_work[idx].msg = NULL;
4109 }
Yun Parkfec73dc2017-09-06 10:40:07 -07004110
Yun Parke4239802018-01-09 11:01:40 -08004111 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004112 return 0;
4113}
4114
4115/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004116 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
4117 *
4118 * Deinit basic IPA UC host side to be in sync reloaded FW during
4119 * SSR
4120 *
4121 * Return: 0 - Success
4122 */
4123int hdd_ipa_uc_ssr_deinit(void)
4124{
4125 int ret;
4126
4127 cds_ssr_protect(__func__);
4128 ret = __hdd_ipa_uc_ssr_deinit();
4129 cds_ssr_unprotect(__func__);
4130
4131 return ret;
4132}
4133
4134/**
4135 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004136 *
4137 * Init basic IPA UC host side to be in sync with reloaded FW after
4138 * SSR to resume IPA UC operations
4139 *
4140 * Return: 0 - Success
4141 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004142static int __hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004143{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004144
Arun Khandavallicc544b32017-01-30 19:52:16 +05304145 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4146 int i;
4147 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05304148
Yun Parke4239802018-01-09 11:01:40 -08004149 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07004150
Arun Khandavallicc544b32017-01-30 19:52:16 +05304151 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
4152 return 0;
4153
Arun Khandavallicc544b32017-01-30 19:52:16 +05304154 /* Create the interface context */
4155 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4156 iface_context = &hdd_ipa->iface_context[i];
4157 iface_context->hdd_ipa = hdd_ipa;
4158 iface_context->cons_client =
4159 hdd_ipa_adapter_2_client[i].cons_client;
4160 iface_context->prod_client =
4161 hdd_ipa_adapter_2_client[i].prod_client;
4162 iface_context->iface_id = i;
4163 iface_context->adapter = NULL;
4164 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05304165
4166 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4167 hdd_ipa->resource_loading = false;
4168 hdd_ipa->resource_unloading = false;
4169 hdd_ipa->sta_connected = 0;
4170 hdd_ipa->ipa_pipes_down = true;
4171 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05304172 }
4173
Yun Parke4239802018-01-09 11:01:40 -08004174 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004175 return 0;
4176}
Leo Chang3bc8fed2015-11-13 10:59:47 -08004177
4178/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004179 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
4180 *
4181 * Init basic IPA UC host side to be in sync with reloaded FW after
4182 * SSR to resume IPA UC operations
4183 *
4184 * Return: 0 - Success
4185 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004186int hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004187{
4188 int ret;
4189
4190 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05304191 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004192 cds_ssr_unprotect(__func__);
4193
4194 return ret;
4195}
4196
4197/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004198 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004199 * @hdd_ctx: Global HDD context
4200 * @tx_packets: Number of packets transmitted in the last sample period
4201 * @rx_packets: Number of packets received in the last sample period
4202 *
4203 * Return: 0 on success, negative errno on error
4204 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07004205static int __hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx,
4206 uint64_t tx_packets,
4207 uint64_t rx_packets)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004208{
4209 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004210 struct hdd_ipa_priv *hdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07004211 qdf_ipa_rm_perf_profile_t profile;
Yun Parkb4f591d2017-03-29 15:51:01 -07004212 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004213 int ret;
4214
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004215 if (wlan_hdd_validate_context(hdd_ctx))
4216 return 0;
4217
4218 hdd_ipa = hdd_ctx->hdd_ipa;
4219
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004220 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
4221 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
4222 return 0;
4223
4224 memset(&profile, 0, sizeof(profile));
4225
4226 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
4227 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
4228 else if (tx_packets >
4229 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
4230 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
4231 else
4232 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
4233
4234 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
4235 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
4236 else if (rx_packets >
4237 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
4238 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
4239 else
4240 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
4241
Yun Parkec845302016-12-15 09:22:57 -08004242 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004243 "CONS perf curr: %d, next: %d",
4244 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08004245 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004246 "PROD perf curr: %d, next: %d",
4247 hdd_ipa->curr_prod_bw, next_prod_bw);
4248
4249 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08004250 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07004252 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS,
4253 next_cons_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004255 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004256
4257 return ret;
4258 }
4259 hdd_ipa->curr_cons_bw = next_cons_bw;
4260 hdd_ipa->stats.num_cons_perf_req++;
4261 }
4262
4263 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08004264 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004265 hdd_ipa->curr_prod_bw, next_prod_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07004266 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD,
4267 next_prod_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004268 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08004269 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004270 return ret;
4271 }
4272 hdd_ipa->curr_prod_bw = next_prod_bw;
4273 hdd_ipa->stats.num_prod_perf_req++;
4274 }
4275
4276 return 0;
4277}
4278
4279/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004280 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
4281 * @hdd_ctx: Global HDD context
4282 * @tx_packets: Number of packets transmitted in the last sample period
4283 * @rx_packets: Number of packets received in the last sample period
4284 *
4285 * Return: 0 on success, negative errno on error
4286 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004287int hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004288 uint64_t rx_packets)
4289{
4290 int ret;
4291
4292 cds_ssr_protect(__func__);
4293 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
4294 cds_ssr_unprotect(__func__);
4295
4296 return ret;
4297}
4298
tfyu0380a972017-07-13 18:19:37 +08004299#ifdef QCA_CONFIG_SMP
4300static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4301{
4302 return netif_rx_ni(skb);
4303}
4304#else
4305static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4306{
4307 struct iphdr *ip_h;
4308 static atomic_t softirq_mitigation_cntr =
4309 ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH);
4310 int result;
4311
4312 ip_h = (struct iphdr *)(skb->data);
4313 if ((skb->protocol == htons(ETH_P_IP)) &&
4314 (ip_h->protocol == IPPROTO_ICMP)) {
4315 result = netif_rx_ni(skb);
4316 } else {
4317 /* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets
4318 * to avoid excessive softirq's.
4319 */
4320 if (atomic_dec_and_test(&softirq_mitigation_cntr)) {
4321 result = netif_rx_ni(skb);
4322 atomic_set(&softirq_mitigation_cntr,
4323 IPA_WLAN_RX_SOFTIRQ_THRESH);
4324 } else {
4325 result = netif_rx(skb);
4326 }
4327 }
4328
4329 return result;
4330}
4331#endif
4332
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004333/**
4334 * hdd_ipa_send_skb_to_network() - Send skb to kernel
4335 * @skb: network buffer
4336 * @adapter: network adapter
4337 *
4338 * Called when a network buffer is received which should not be routed
4339 * to the IPA module.
4340 *
4341 * Return: None
4342 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304343static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004344 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004345{
tfyu0380a972017-07-13 18:19:37 +08004346 int result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004347 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4348 unsigned int cpu_index;
4349
4350 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Jeff Johnson36e74c42017-09-18 08:15:42 -07004351 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%pK",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004352 adapter);
Yun Park46255682017-10-09 15:56:34 -07004353 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004354 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004355 return;
4356 }
4357
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004358 if (cds_is_driver_unloading()) {
Yun Park46255682017-10-09 15:56:34 -07004359 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004360 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004361 return;
4362 }
4363
4364 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
4365 skb->dev = adapter->dev;
4366 skb->protocol = eth_type_trans(skb, skb->dev);
4367 skb->ip_summed = CHECKSUM_NONE;
4368
4369 cpu_index = wlan_hdd_get_cpu();
4370
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004371 ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index];
tfyu0380a972017-07-13 18:19:37 +08004372 result = hdd_ipa_aggregated_rx_ind(skb);
4373 if (result == NET_RX_SUCCESS)
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004374 ++adapter->hdd_stats.tx_rx_stats.rx_delivered[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004375 else
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004376 ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004377
Yun Park46255682017-10-09 15:56:34 -07004378 hdd_ipa->ipa_rx_net_send_count++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004379}
4380
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004381/**
Leo Chang69c39692016-10-12 20:11:12 -07004382 * hdd_ipa_forward() - handle packet forwarding to wlan tx
4383 * @hdd_ipa: pointer to hdd ipa context
4384 * @adapter: network adapter
4385 * @skb: data pointer
4386 *
4387 * if exception packet has set forward bit, copied new packet should be
4388 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
4389 * put into pm queue and tx procedure will be differed
4390 *
4391 * Return: None
4392 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07004393static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004394 struct hdd_adapter *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07004395{
Leo Chang69c39692016-10-12 20:11:12 -07004396 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
4397
Leo Chang69c39692016-10-12 20:11:12 -07004398 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Yun Park01deb2c2017-06-14 15:21:44 -07004399
4400 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
4401 qdf_nbuf_ipa_owned_set(skb);
4402
Yun Park46255682017-10-09 15:56:34 -07004403 /* WLAN subsystem is in suspend, put in queue */
Leo Chang69c39692016-10-12 20:11:12 -07004404 if (hdd_ipa->suspended) {
4405 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Yun Park46255682017-10-09 15:56:34 -07004406 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4407 "Tx in suspend, put in queue");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004408 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
4409 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07004410 pm_tx_cb->exception = true;
4411 pm_tx_cb->adapter = adapter;
4412 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004413 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07004414 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4415 hdd_ipa->stats.num_tx_queued++;
4416 } else {
4417 /* Resume, put packet into WLAN TX */
4418 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004419 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07004420 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07004421 "packet Tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08004422 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07004423 } else {
Yun Parkb187d542016-11-14 18:10:04 -08004424 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07004425 }
4426 }
4427}
4428
4429/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004430 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
4431 * @hdd_ipa: pointer to HDD IPA struct
4432 * @adapter: hdd adapter pointer
4433 * @desc: Firmware descriptor
4434 * @skb: Data buffer
4435 *
4436 * Return:
4437 * HDD_IPA_FORWARD_PKT_NONE
4438 * HDD_IPA_FORWARD_PKT_DISCARD
4439 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
4440 *
4441 */
4442
4443static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
4444 struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004445 struct hdd_adapter *adapter,
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004446 uint8_t desc,
4447 qdf_nbuf_t skb)
4448{
4449 int ret = HDD_IPA_FORWARD_PKT_NONE;
Yun Park0dad1002017-07-14 14:57:01 -07004450 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
4451 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004452
4453 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304454 if (!ol_txrx_fwd_desc_thresh_check(
Yun Park0dad1002017-07-14 14:57:01 -07004455 (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc,
4456 (struct cdp_pdev *)pdev,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004457 adapter->session_id))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304458 /* Drop the packet*/
4459 hdd_ipa->stats.num_tx_fwd_err++;
4460 kfree_skb(skb);
4461 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4462 return ret;
4463 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004464 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
4465 "Forward packet to Tx (fw_desc=%d)", desc);
4466 hdd_ipa->ipa_tx_forward++;
4467
4468 if ((desc & FW_RX_DESC_DISCARD_M)) {
4469 hdd_ipa_forward(hdd_ipa, adapter, skb);
Yun Park46255682017-10-09 15:56:34 -07004470 hdd_ipa->ipa_rx_internal_drop_count++;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004471 hdd_ipa->ipa_rx_discard++;
4472 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4473 } else {
4474 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004475
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004476 if (cloned_skb)
4477 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
4478 else
4479 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07004480 "tx skb alloc failed");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004481 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
4482 }
4483 }
4484
4485 return ret;
4486}
4487
4488/**
Yun Park637d6482016-10-05 10:51:33 -07004489 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004490 * @priv: pointer to private data registered with IPA (we register a
4491 * pointer to the global IPA context)
4492 * @evt: the IPA event which triggered the callback
4493 * @data: data associated with the event
4494 *
4495 * Return: None
4496 */
Yun Park6c86a662017-10-05 16:09:15 -07004497static void __hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
4498 unsigned long data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004499{
4500 struct hdd_ipa_priv *hdd_ipa = NULL;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004501 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304502 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004503 uint8_t iface_id;
4504 uint8_t session_id;
4505 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004506 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07004507 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004508
4509 hdd_ipa = (struct hdd_ipa_priv *)priv;
4510
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08004511 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
4512 return;
4513
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004514 switch (evt) {
4515 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05304516 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07004517
4518 /*
4519 * When SSR is going on or driver is unloading,
4520 * just drop the packets.
4521 */
4522 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4523 if (0 != status) {
4524 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4525 "Invalid context: drop packet");
Yun Park46255682017-10-09 15:56:34 -07004526 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004527 kfree_skb(skb);
4528 return;
4529 }
4530
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004531 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4532 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004533 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004534 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004535 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4536 session_id, iface_id);
4537 } else {
4538 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4539 }
4540
4541 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304542 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004543 "IPA_RECEIVE: Invalid iface_id: %u",
4544 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004545 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004546 "w2i -- skb",
4547 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Yun Park46255682017-10-09 15:56:34 -07004548 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004549 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004550 return;
4551 }
4552
4553 iface_context = &hdd_ipa->iface_context[iface_id];
4554 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08004555 if (!adapter) {
4556 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4557 "IPA_RECEIVE: Adapter is NULL");
Yun Park46255682017-10-09 15:56:34 -07004558 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Park16a78262017-02-01 12:15:03 -08004559 kfree_skb(skb);
4560 return;
4561 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004562
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304563 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004564 "w2i -- skb",
4565 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004566 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4567 hdd_ipa->stats.num_rx_excep++;
4568 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4569 } else {
4570 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4571 }
4572
4573 iface_context->stats.num_rx_ipa_excep++;
4574
4575 /* Disable to forward Intra-BSS Rx packets when
4576 * ap_isolate=1 in hostapd.conf
4577 */
Jeff Johnsonb9424862017-10-30 08:49:35 -07004578 if (!adapter->session.ap.disable_intrabss_fwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004579 /*
4580 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4581 * all Rx packets to IPA uC, which need to be forwarded
4582 * to other interface.
4583 * And, IPA driver will send back to WLAN host driver
4584 * through exception pipe with fw_desc field set by FW.
4585 * Here we are checking fw_desc field for FORWARD bit
4586 * set, and forward to Tx. Then copy to kernel stack
4587 * only when DISCARD bit is not set.
4588 */
4589 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004590 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4591 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4592 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004593 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004595 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004596 "Intra-BSS FWD is disabled-skip forward to Tx");
4597 }
4598
4599 hdd_ipa_send_skb_to_network(skb, adapter);
4600 break;
4601
4602 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304603 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004604 "w2i cb wrong event: 0x%x", evt);
4605 return;
4606 }
4607}
4608
4609/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004610 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4611 * @priv: pointer to private data registered with IPA (we register a
4612 * pointer to the global IPA context)
4613 * @evt: the IPA event which triggered the callback
4614 * @data: data associated with the event
4615 *
4616 * Return: None
4617 */
Yun Park6c86a662017-10-05 16:09:15 -07004618static void hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Yun Parkf8d6a122016-10-11 15:49:43 -07004619 unsigned long data)
4620{
4621 cds_ssr_protect(__func__);
4622 __hdd_ipa_w2i_cb(priv, evt, data);
4623 cds_ssr_unprotect(__func__);
4624}
4625
4626/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004627 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4628 * @skb: packet buffer which was transmitted
4629 *
4630 * Return: None
4631 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304632void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004633{
4634 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07004635 qdf_ipa_rx_data_t *ipa_tx_desc;
Yun Park52b2b992016-09-22 15:49:51 -07004636 struct hdd_ipa_tx_desc *tx_desc;
4637 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638
Yun Park52b2b992016-09-22 15:49:51 -07004639 if (!qdf_nbuf_ipa_owned_get(skb)) {
4640 dev_kfree_skb_any(skb);
4641 return;
4642 }
4643
4644 /* Get Tx desc pointer from SKB CB */
4645 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4646 tx_desc = hdd_ipa->tx_desc_list + id;
4647 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4648
4649 /* Return Tx Desc to IPA */
4650 ipa_free_skb(ipa_tx_desc);
4651
4652 /* Return to free tx desc list */
4653 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4654 tx_desc->ipa_tx_desc_ptr = NULL;
4655 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4656 hdd_ipa->stats.num_tx_desc_q_cnt--;
4657 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658
4659 hdd_ipa->stats.num_tx_comp_cnt++;
4660
4661 atomic_dec(&hdd_ipa->tx_ref_cnt);
4662
Yun Park84c0ceb2018-01-11 10:37:10 -08004663 hdd_ipa_wdi_rm_try_release(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004664}
4665
4666/**
4667 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4668 * @iface_context: interface-specific IPA context
4669 * @ipa_tx_desc: packet data descriptor
4670 *
4671 * Return: None
4672 */
4673static void hdd_ipa_send_pkt_to_tl(
4674 struct hdd_ipa_iface_context *iface_context,
Yun Park6c86a662017-10-05 16:09:15 -07004675 qdf_ipa_rx_data_t *ipa_tx_desc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004676{
4677 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004678 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304679 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004680 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004681
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304682 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004683 adapter = iface_context->adapter;
4684 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304685 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004686 ipa_free_skb(ipa_tx_desc);
4687 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304688 qdf_spin_unlock_bh(&iface_context->interface_lock);
Yun Park84c0ceb2018-01-11 10:37:10 -08004689 hdd_ipa_wdi_rm_try_release(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004690 return;
4691 }
4692
4693 /*
4694 * During CAC period, data packets shouldn't be sent over the air so
4695 * drop all the packets here
4696 */
hqu70708ab2017-10-10 17:52:01 +08004697 if (QDF_SAP_MODE == adapter->device_mode ||
4698 QDF_P2P_GO_MODE == adapter->device_mode) {
4699 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4700 ipa_free_skb(ipa_tx_desc);
4701 qdf_spin_unlock_bh(&iface_context->interface_lock);
4702 iface_context->stats.num_tx_cac_drop++;
Yun Park84c0ceb2018-01-11 10:37:10 -08004703 hdd_ipa_wdi_rm_try_release(hdd_ipa);
hqu70708ab2017-10-10 17:52:01 +08004704 return;
4705 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004706 }
4707
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004708 ++adapter->stats.tx_packets;
4709
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304710 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004711
Yun Park6c86a662017-10-05 16:09:15 -07004712 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004713
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304714 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004715
4716 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304717 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004718 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304719 qdf_nbuf_mapped_paddr_set(skb,
Yun Park6c86a662017-10-05 16:09:15 -07004720 QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc)
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004721 + HDD_IPA_WLAN_FRAG_HEADER
4722 + HDD_IPA_WLAN_IPA_HEADER);
Yun Park6c86a662017-10-05 16:09:15 -07004723 QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004724 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4725 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304726 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004727
Yun Park52b2b992016-09-22 15:49:51 -07004728 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4729 /* get free Tx desc and assign ipa_tx_desc pointer */
4730 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4731 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4732 struct hdd_ipa_tx_desc, link);
4733 list_del(&tx_desc->link);
4734 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4735 hdd_ipa->stats.num_tx_desc_q_cnt++;
4736 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4737 /* Store Tx Desc index into SKB CB */
4738 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4739 } else {
4740 hdd_ipa->stats.num_tx_desc_error++;
4741 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Yun Park52b2b992016-09-22 15:49:51 -07004742 ipa_free_skb(ipa_tx_desc);
Yun Park84c0ceb2018-01-11 10:37:10 -08004743 hdd_ipa_wdi_rm_try_release(hdd_ipa);
Yun Park52b2b992016-09-22 15:49:51 -07004744 return;
4745 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004746
Yun Park6c86a662017-10-05 16:09:15 -07004747 adapter->stats.tx_bytes += QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004748
Leo Changfdb45c32016-10-28 11:09:23 -07004749 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Yun Park6c86a662017-10-05 16:09:15 -07004750 (struct cdp_vdev *)iface_context->tl_context,
4751 QDF_IPA_RX_DATA_SKB(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004752 if (skb) {
jiad05c1e812017-08-01 16:48:52 +08004753 qdf_nbuf_free(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004754 iface_context->stats.num_tx_err++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004755 return;
4756 }
4757
4758 atomic_inc(&hdd_ipa->tx_ref_cnt);
4759
4760 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004761}
4762
4763/**
Leo Chang11545d62016-10-17 14:53:50 -07004764 * hdd_ipa_is_present() - get IPA hw status
4765 * @hdd_ctx: pointer to hdd context
4766 *
4767 * ipa_uc_reg_rdyCB is not directly designed to check
4768 * ipa hw status. This is an undocumented function which
4769 * has confirmed with IPA team.
4770 *
4771 * Return: true - ipa hw present
4772 * false - ipa hw not present
4773 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004774bool hdd_ipa_is_present(struct hdd_context *hdd_ctx)
Leo Chang11545d62016-10-17 14:53:50 -07004775{
jiad4ab698b2018-02-02 13:43:09 +08004776 /*
4777 * Check if ipa hw is enabled
4778 * TODO: Add support for WDI unified API
4779 */
4780 if (ipa_uc_reg_rdyCB(NULL) != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004781 return true;
4782 else
4783 return false;
4784}
4785
4786/**
Leo Chang69c39692016-10-12 20:11:12 -07004787 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004788 * @work: pointer to the scheduled work
4789 *
4790 * Called during PM resume to send packets to TL which were queued
4791 * while host was in the process of suspending.
4792 *
4793 * Return: None
4794 */
Leo Chang69c39692016-10-12 20:11:12 -07004795static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004796{
4797 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4798 struct hdd_ipa_priv,
4799 pm_work);
4800 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304801 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004802 uint32_t dequeued = 0;
4803
Leo Chang69c39692016-10-12 20:11:12 -07004804 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4805 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304806 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304807 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4808 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304809 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004810
4811 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004812 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004813 if (pm_tx_cb->exception) {
Yun Park46255682017-10-09 15:56:34 -07004814 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4815 "Flush Exception");
Govind Singh1dab23b2017-08-12 13:31:00 +05304816 if (pm_tx_cb->adapter->dev)
4817 hdd_softap_hard_start_xmit(skb,
4818 pm_tx_cb->adapter->dev);
Govind Singh02075942017-08-15 11:13:28 +05304819 else
4820 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004821 } else {
4822 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004823 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004824 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304825 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004826 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304827 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004828 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4829 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004830
4831 hdd_ipa->stats.num_tx_dequeued += dequeued;
4832 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4833 hdd_ipa->stats.num_max_pm_queue = dequeued;
4834}
4835
4836/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004837 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004838 * @priv: pointer to private data registered with IPA (we register a
4839 * pointer to the interface-specific IPA context)
4840 * @evt: the IPA event which triggered the callback
4841 * @data: data associated with the event
4842 *
4843 * Return: None
4844 */
Yun Park6c86a662017-10-05 16:09:15 -07004845static void __hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
4846 unsigned long data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004847{
4848 struct hdd_ipa_priv *hdd_ipa = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07004849 qdf_ipa_rx_data_t *ipa_tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004850 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304851 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004852 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304853 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004854
Mukul Sharma81661ae2015-10-30 20:26:02 +05304855 iface_context = (struct hdd_ipa_iface_context *)priv;
Yun Park6c86a662017-10-05 16:09:15 -07004856 ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004857 hdd_ipa = iface_context->hdd_ipa;
4858
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004859 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004860 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4861 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004862 iface_context->stats.num_tx_drop++;
4863 return;
4864 }
4865
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004866 /*
4867 * When SSR is going on or driver is unloading, just drop the packets.
4868 * During SSR, there is no use in queueing the packets as STA has to
4869 * connect back any way
4870 */
4871 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304872 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004873 ipa_free_skb(ipa_tx_desc);
4874 iface_context->stats.num_tx_drop++;
4875 return;
4876 }
4877
Yun Park6c86a662017-10-05 16:09:15 -07004878 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004879
Yun Parkb187d542016-11-14 18:10:04 -08004880 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4881 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004882
4883 /*
4884 * If PROD resource is not requested here then there may be cases where
4885 * IPA hardware may be clocked down because of not having proper
4886 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4887 * workaround to request PROD resource while data is going over CONS
4888 * pipe to prevent the IPA hardware clockdown.
4889 */
Yun Park84c0ceb2018-01-11 10:37:10 -08004890 hdd_ipa_wdi_rm_request(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004891
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304892 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004893 /*
4894 * If host is still suspended then queue the packets and these will be
4895 * drained later when resume completes. When packet is arrived here and
4896 * host is suspended, this means that there is already resume is in
4897 * progress.
4898 */
4899 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304900 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004901 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4902 pm_tx_cb->iface_context = iface_context;
4903 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304904 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004905 hdd_ipa->stats.num_tx_queued++;
4906
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304907 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004908 return;
4909 }
4910
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304911 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004912
4913 /*
4914 * If we are here means, host is not suspended, wait for the work queue
4915 * to finish.
4916 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004917 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004918
4919 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4920}
4921
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004922/*
4923 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4924 * @priv: pointer to private data registered with IPA (we register a
4925 * pointer to the interface-specific IPA context)
4926 * @evt: the IPA event which triggered the callback
4927 * @data: data associated with the event
4928 *
4929 * Return: None
4930 */
Yun Park6c86a662017-10-05 16:09:15 -07004931static void hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004932 unsigned long data)
4933{
4934 cds_ssr_protect(__func__);
4935 __hdd_ipa_i2w_cb(priv, evt, data);
4936 cds_ssr_unprotect(__func__);
4937}
4938
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004939/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004940 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004941 * @hdd_ctx: Global HDD context
4942 *
4943 * Return: 0 on success, negativer errno on error
4944 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004945static int __hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004946{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004947 struct hdd_ipa_priv *hdd_ipa;
4948
4949 if (wlan_hdd_validate_context(hdd_ctx))
4950 return 0;
4951
4952 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004953
4954 if (!hdd_ipa_is_enabled(hdd_ctx))
4955 return 0;
4956
4957 /*
4958 * Check if IPA is ready for suspend, If we are here means, there is
4959 * high chance that suspend would go through but just to avoid any race
4960 * condition after suspend started, these checks are conducted before
4961 * allowing to suspend.
4962 */
4963 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4964 return -EAGAIN;
4965
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304966 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004967
4968 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304969 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004970 return -EAGAIN;
4971 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304972 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004973
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304974 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004975 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304976 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004977
4978 return 0;
4979}
4980
4981/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004982 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4983 * @hdd_ctx: Global HDD context
4984 *
4985 * Return: 0 on success, negativer errno on error
4986 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004987int hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004988{
4989 int ret;
4990
4991 cds_ssr_protect(__func__);
4992 ret = __hdd_ipa_suspend(hdd_ctx);
4993 cds_ssr_unprotect(__func__);
4994
4995 return ret;
4996}
4997
4998/**
4999 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005000 * hdd_ctx: Global HDD context
5001 *
5002 * Return: 0 on success, negative errno on error
5003 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005004static int __hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005005{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005006 struct hdd_ipa_priv *hdd_ipa;
5007
5008 if (wlan_hdd_validate_context(hdd_ctx))
5009 return 0;
5010
5011 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005012
5013 if (!hdd_ipa_is_enabled(hdd_ctx))
5014 return 0;
5015
5016 schedule_work(&hdd_ipa->pm_work);
5017
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305018 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005019 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305020 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005021
5022 return 0;
5023}
5024
5025/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005026 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
5027 * hdd_ctx: Global HDD context
5028 *
5029 * Return: 0 on success, negative errno on error
5030 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005031int hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005032{
5033 int ret;
5034
5035 cds_ssr_protect(__func__);
5036 ret = __hdd_ipa_resume(hdd_ctx);
5037 cds_ssr_unprotect(__func__);
5038
5039 return ret;
5040}
5041
5042/**
Yun Park52b2b992016-09-22 15:49:51 -07005043 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
5044 * @hdd_ipa: Global HDD IPA context
5045 *
5046 * Return: 0 on success, negative errno on error
5047 */
5048static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
5049{
5050 int i;
5051 uint32_t max_desc_cnt;
5052 struct hdd_ipa_tx_desc *tmp_desc;
5053
Yun Parkd9c528e2017-08-30 16:34:57 -07005054 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
Yun Park52b2b992016-09-22 15:49:51 -07005055
5056 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
5057
jiad14fe4fb2017-08-08 13:33:14 +08005058 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc) *
Yun Parkd9c528e2017-08-30 16:34:57 -07005059 max_desc_cnt);
Yun Park52b2b992016-09-22 15:49:51 -07005060
5061 if (!tmp_desc) {
5062 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkd9c528e2017-08-30 16:34:57 -07005063 "Free Tx descriptor allocation failed");
Yun Park52b2b992016-09-22 15:49:51 -07005064 return -ENOMEM;
5065 }
5066
5067 hdd_ipa->tx_desc_list = tmp_desc;
5068
5069 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07005070 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07005071 tmp_desc->id = i;
5072 tmp_desc->ipa_tx_desc_ptr = NULL;
5073 list_add_tail(&tmp_desc->link,
5074 &hdd_ipa->free_tx_desc_head);
5075 tmp_desc++;
5076 }
5077
5078 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
5079 hdd_ipa->stats.num_tx_desc_error = 0;
5080
5081 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
5082
5083 return 0;
5084}
5085
Yun Park9281cb72017-11-30 11:14:30 -08005086#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Yun Park52b2b992016-09-22 15:49:51 -07005087/**
Yun Park9281cb72017-11-30 11:14:30 -08005088 * hdd_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005089 * @hdd_ipa: Global HDD IPA context
Yun Park9281cb72017-11-30 11:14:30 -08005090 * @desc_fifo_sz: Number of descriptors
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005091 *
5092 * Return: 0 on success, negative errno on error
5093 */
Yun Park9281cb72017-11-30 11:14:30 -08005094static int hdd_ipa_setup_tx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
5095 int32_t desc_fifo_sz)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005096{
5097 int i, ret = 0;
Yun Park6c86a662017-10-05 16:09:15 -07005098 qdf_ipa_sys_connect_params_t *ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005099
5100 /*setup TX pipes */
5101 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5102 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
5103
5104 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
5105 ipa->desc_fifo_sz = desc_fifo_sz;
5106 ipa->priv = &hdd_ipa->iface_context[i];
5107 ipa->notify = hdd_ipa_i2w_cb;
5108
5109 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5110 ipa->ipa_ep_cfg.hdr.hdr_len =
5111 HDD_IPA_UC_WLAN_TX_HDR_LEN;
5112 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
5113 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
5114 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
5115 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
5116 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
5117 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
5118 } else {
5119 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
5120 }
5121 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
5122
5123 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
5124 ipa->keep_ipa_awake = 1;
5125
Yun Park84c0ceb2018-01-11 10:37:10 -08005126 ret = hdd_ipa_wdi_setup_sys_pipe(
5127 hdd_ipa, ipa,
5128 &hdd_ipa->sys_pipe[i].conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005129 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005130 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5131 "Failed for pipe %d ret: %d", i, ret);
Yun Park9281cb72017-11-30 11:14:30 -08005132 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005133 }
5134 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
5135 }
5136
Yun Park9281cb72017-11-30 11:14:30 -08005137 return ret;
5138}
5139#else
5140/**
5141 * hdd_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
5142 * @hdd_ipa: Global HDD IPA context
5143 * @desc_fifo_sz: Number of descriptors
5144 *
5145 * Return: 0 on success, negative errno on error
5146 */
5147static int hdd_ipa_setup_tx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
5148 int32_t desc_fifo_sz)
5149{
5150 /*
5151 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
5152 * is enabled, where per vdev descriptors are supported in firmware.
5153 */
5154 return 0;
5155}
5156#endif
5157
5158/**
5159 * hdd_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
5160 * @hdd_ipa: Global HDD IPA context
5161 * @desc_fifo_sz: Number of descriptors
5162 *
5163 * Return: 0 on success, negative errno on error
5164 */
5165static int hdd_ipa_setup_rx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
5166 int32_t desc_fifo_sz)
5167{
5168 int ret = 0;
5169 qdf_ipa_sys_connect_params_t *ipa;
5170
5171 /*
5172 * Hard code it here, this can be extended if in case
5173 * PROD pipe is also per interface.
5174 * Right now there is no advantage of doing this.
5175 */
5176 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
5177
5178 ipa->client = IPA_CLIENT_WLAN1_PROD;
5179
5180 ipa->desc_fifo_sz = desc_fifo_sz;
5181 ipa->priv = hdd_ipa;
5182 ipa->notify = hdd_ipa_w2i_cb;
5183
5184 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
5185 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
5186 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
5187 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
5188
5189 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
5190 ipa->keep_ipa_awake = 1;
5191
Yun Park84c0ceb2018-01-11 10:37:10 -08005192 ret = hdd_ipa_wdi_setup_sys_pipe(hdd_ipa, ipa,
Yun Park9281cb72017-11-30 11:14:30 -08005193 &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl);
5194 if (ret) {
5195 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park84c0ceb2018-01-11 10:37:10 -08005196 "Failed for RX pipe: %d", ret);
Yun Park9281cb72017-11-30 11:14:30 -08005197 return ret;
5198 }
5199 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
5200
5201 return ret;
5202}
5203
5204/**
5205 * hdd_ipa_setup_sys_pipe() - Setup all IPA system pipes
5206 * @hdd_ipa: Global HDD IPA context
5207 *
5208 * Return: 0 on success, negative errno on error
5209 */
5210static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
5211{
5212 int i = HDD_IPA_MAX_IFACE, ret = 0;
5213 uint32_t desc_fifo_sz;
5214
5215 /* The maximum number of descriptors that can be provided to a BAM at
5216 * once is one less than the total number of descriptors that the buffer
5217 * can contain.
5218 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
5219 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
5220 * be provided at once.
5221 * Because of above requirement, one extra descriptor will be added to
5222 * make sure hardware always has one descriptor.
5223 */
5224 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
Yuanyuan Liu23a8eec2017-12-15 16:01:12 -08005225 + SPS_DESC_SIZE;
Yun Park9281cb72017-11-30 11:14:30 -08005226
5227 ret = hdd_ipa_setup_tx_sys_pipe(hdd_ipa, desc_fifo_sz);
5228 if (ret) {
5229 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5230 "Failed for TX pipe: %d", ret);
5231 goto setup_sys_pipe_fail;
5232 }
5233
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005234 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park9281cb72017-11-30 11:14:30 -08005235 ret = hdd_ipa_setup_rx_sys_pipe(hdd_ipa, desc_fifo_sz);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005236 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305237 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park9281cb72017-11-30 11:14:30 -08005238 "Failed for RX pipe: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005239 goto setup_sys_pipe_fail;
5240 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005241 }
5242
Yun Parkd9c528e2017-08-30 16:34:57 -07005243 /* Allocate free Tx desc list */
Yun Park52b2b992016-09-22 15:49:51 -07005244 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
5245 if (ret)
5246 goto setup_sys_pipe_fail;
5247
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005248 return ret;
5249
5250setup_sys_pipe_fail:
5251
Yun Park9281cb72017-11-30 11:14:30 -08005252 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
5253 if (hdd_ipa->sys_pipe[i].conn_hdl_valid)
Yun Park84c0ceb2018-01-11 10:37:10 -08005254 hdd_ipa_wdi_teardown_sys_pipe(
5255 hdd_ipa, hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305256 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005257 sizeof(struct hdd_ipa_sys_pipe));
5258 }
5259
5260 return ret;
5261}
5262
5263/**
5264 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
5265 * @hdd_ipa: Global HDD IPA context
5266 *
5267 * Return: None
5268 */
5269static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
5270{
5271 int ret = 0, i;
Yun Parkd9c528e2017-08-30 16:34:57 -07005272 uint32_t max_desc_cnt;
Yun Park52b2b992016-09-22 15:49:51 -07005273 struct hdd_ipa_tx_desc *tmp_desc;
Yun Park6c86a662017-10-05 16:09:15 -07005274 qdf_ipa_rx_data_t *ipa_tx_desc;
Yun Park52b2b992016-09-22 15:49:51 -07005275
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005276 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
5277 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
Yun Park84c0ceb2018-01-11 10:37:10 -08005278 ret = hdd_ipa_wdi_teardown_sys_pipe(
5279 hdd_ipa, hdd_ipa->sys_pipe[i].conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005280 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305281 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005282 ret);
5283
5284 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
5285 }
5286 }
Yun Park52b2b992016-09-22 15:49:51 -07005287
5288 if (hdd_ipa->tx_desc_list) {
Yun Parkd9c528e2017-08-30 16:34:57 -07005289 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
5290
Yun Park52b2b992016-09-22 15:49:51 -07005291 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07005292 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07005293 tmp_desc = hdd_ipa->tx_desc_list + i;
5294 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
5295 if (ipa_tx_desc)
5296 ipa_free_skb(ipa_tx_desc);
5297 }
5298 tmp_desc = hdd_ipa->tx_desc_list;
5299 hdd_ipa->tx_desc_list = NULL;
5300 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
5301 hdd_ipa->stats.num_tx_desc_error = 0;
5302 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
5303 qdf_mem_free(tmp_desc);
5304 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005305}
5306
5307/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005308 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
5309 * @iface_context: interface-specific IPA context
5310 *
5311 * Return: None
5312 */
5313static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
5314{
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005315 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07005316
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005317 if (iface_context == NULL)
5318 return;
Orhan K AKYILDIZ3332be32017-05-31 15:36:31 -07005319 if (iface_context->adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
5320 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
5321 "%s: bad adapter(%pK).magic(%d)!",
5322 __func__, iface_context->adapter,
5323 iface_context->adapter->magic);
5324 return;
5325 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005326
Yun Parkb4f591d2017-03-29 15:51:01 -07005327 cdp_ipa_cleanup_iface(cds_get_context(QDF_MODULE_ID_SOC),
5328 iface_context->adapter->dev->name,
5329 hdd_ipa_is_ipv6_enabled(iface_context->hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005330
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305331 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005332 iface_context->adapter->ipa_context = NULL;
5333 iface_context->adapter = NULL;
5334 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305335 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005336 iface_context->ifa_address = 0;
5337 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305338 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005339 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05305340 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005341 }
5342 iface_context->hdd_ipa->num_iface--;
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005343 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005344 iface_context->hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005345}
5346
5347/**
5348 * hdd_ipa_setup_iface() - Setup IPA on a given interface
5349 * @hdd_ipa: HDD IPA global context
5350 * @adapter: Interface upon which IPA is being setup
5351 * @sta_id: Station ID of the API instance
5352 *
5353 * Return: 0 on success, negative errno value on error
5354 */
5355static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07005356 struct hdd_adapter *adapter, uint8_t sta_id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005357{
5358 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park0dad1002017-07-14 14:57:01 -07005359 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
5360 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005361 void *tl_context = NULL;
Yun Park84c0ceb2018-01-11 10:37:10 -08005362 uint8_t iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005363 int i, ret = 0;
5364
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005365 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07005366
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005367 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
5368 * channel change indication. Since these indications are sent by lower
5369 * layer as SAP updates and IPA doesn't have to do anything for these
5370 * updates so ignoring!
5371 */
Krunal Sonibe766b02016-03-10 13:00:44 -08005372 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005373 return 0;
5374
5375 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5376 if (hdd_ipa->iface_context[i].adapter == NULL) {
5377 iface_context = &(hdd_ipa->iface_context[i]);
5378 break;
5379 }
5380 }
5381
5382 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305383 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005384 "All the IPA interfaces are in use");
5385 ret = -ENOMEM;
5386 goto end;
5387 }
5388
5389 adapter->ipa_context = iface_context;
5390 iface_context->adapter = adapter;
5391 iface_context->sta_id = sta_id;
Yun Park84c0ceb2018-01-11 10:37:10 -08005392 iface_id = iface_context->iface_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08005393 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Yun Park0dad1002017-07-14 14:57:01 -07005394 soc, (struct cdp_pdev *)pdev, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005395 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305396 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005397 "Not able to get TL context sta_id: %d", sta_id);
5398 ret = -EINVAL;
5399 goto end;
5400 }
5401
5402 iface_context->tl_context = tl_context;
5403
Yun Parkb4f591d2017-03-29 15:51:01 -07005404 ret = cdp_ipa_setup_iface(cds_get_context(QDF_MODULE_ID_SOC),
5405 adapter->dev->name, adapter->dev->dev_addr,
5406 iface_context->prod_client,
5407 iface_context->cons_client,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005408 adapter->session_id,
Yun Parkb4f591d2017-03-29 15:51:01 -07005409 hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx));
Yun Park84c0ceb2018-01-11 10:37:10 -08005410 if (ret) {
5411 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5412 "IPA interface setup failed: ret=%d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005413 goto end;
Yun Park84c0ceb2018-01-11 10:37:10 -08005414 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005415
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005416 hdd_ipa->num_iface++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005417
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005418 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005419 hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005420 return ret;
5421
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005422end:
5423 if (iface_context)
5424 hdd_ipa_cleanup_iface(iface_context);
5425 return ret;
5426}
5427
Yun Parka27049a2016-10-11 12:30:49 -07005428#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005429/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005430 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Jeff Johnson4929cd92017-10-06 19:21:57 -07005431 * @hdd_ctx: HDD context
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005432 * @mcc_mode: 0=MCC/1=SCC
5433 *
5434 * Return: 0 on success, negative errno value on error
5435 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07005436static int __hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx,
5437 bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005438{
Jeff Johnson089d0432017-10-02 13:27:21 -07005439 struct hdd_adapter *adapter;
Yun Park6c86a662017-10-05 16:09:15 -07005440 qdf_ipa_msg_meta_t meta;
5441 qdf_ipa_wlan_msg_t *msg;
5442
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005443 int ret;
5444
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005445 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005446 return -EINVAL;
5447
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005448 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
5449 return -EINVAL;
5450
5451 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005452 /* Flush TxRx queue for each adapter before switch to SCC */
Dustin Brown920397d2017-12-13 16:27:50 -08005453 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson089d0432017-10-02 13:27:21 -07005454 if (adapter->device_mode == QDF_STA_MODE ||
5455 adapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005456 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnson089d0432017-10-02 13:27:21 -07005457 adapter->device_mode);
5458 hdd_deinit_tx_rx(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005459 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005460 }
5461 }
5462
5463 /* Send SCC/MCC Switching event to IPA */
Yun Park6c86a662017-10-05 16:09:15 -07005464 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
5465 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005466 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005467 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005468 return -ENOMEM;
5469 }
5470
Yun Park6c86a662017-10-05 16:09:15 -07005471 QDF_IPA_MSG_META_MSG_TYPE(&meta) = mcc_mode ?
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005472 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Yun Park6c86a662017-10-05 16:09:15 -07005473 hdd_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005474
Yun Park6c86a662017-10-05 16:09:15 -07005475 ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005476
5477 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005478 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Yun Park6c86a662017-10-05 16:09:15 -07005479 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305480 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005481 }
5482
5483 return ret;
5484}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005485
5486/**
5487 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5488 * @mcc_mode: 0=MCC/1=SCC
5489 *
5490 * Return: 0 on success, negative errno value on error
5491 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005492int hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx, bool mcc_mode)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005493{
5494 int ret;
5495
5496 cds_ssr_protect(__func__);
5497 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5498 cds_ssr_unprotect(__func__);
5499
5500 return ret;
5501}
Yun Parka27049a2016-10-11 12:30:49 -07005502#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005503
5504/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005505 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5506 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5507 *
Yun Park6c86a662017-10-05 16:09:15 -07005508 * Return: qdf_ipa_wlan_event representing the hdd_ipa_wlan_event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005509 */
Yun Park6c86a662017-10-05 16:09:15 -07005510static qdf_ipa_wlan_event_t
Mohit Khannafa99aea2016-05-12 21:43:13 -07005511hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5512{
Yun Park6c86a662017-10-05 16:09:15 -07005513 qdf_ipa_wlan_event_t ipa_event;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005514
5515 switch (hdd_ipa_event_type) {
5516 case HDD_IPA_CLIENT_CONNECT:
5517 ipa_event = WLAN_CLIENT_CONNECT;
5518 break;
5519 case HDD_IPA_CLIENT_DISCONNECT:
5520 ipa_event = WLAN_CLIENT_DISCONNECT;
5521 break;
5522 case HDD_IPA_AP_CONNECT:
5523 ipa_event = WLAN_AP_CONNECT;
5524 break;
5525 case HDD_IPA_AP_DISCONNECT:
5526 ipa_event = WLAN_AP_DISCONNECT;
5527 break;
5528 case HDD_IPA_STA_CONNECT:
5529 ipa_event = WLAN_STA_CONNECT;
5530 break;
5531 case HDD_IPA_STA_DISCONNECT:
5532 ipa_event = WLAN_STA_DISCONNECT;
5533 break;
5534 case HDD_IPA_CLIENT_CONNECT_EX:
5535 ipa_event = WLAN_CLIENT_CONNECT_EX;
5536 break;
5537 case HDD_IPA_WLAN_EVENT_MAX:
5538 default:
5539 ipa_event = IPA_WLAN_EVENT_MAX;
5540 break;
5541 }
5542 return ipa_event;
5543
5544}
5545
5546/**
5547 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005548 * @adapter: adapter upon which the event was received
5549 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005550 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005551 * @mac_address: MAC address associated with the event
5552 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005553 * This function is meant to be called from within wlan_hdd_ipa.c
5554 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005555 * Return: 0 on success, negative errno value on error
5556 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005557static int __hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Yun Park6c86a662017-10-05 16:09:15 -07005558 qdf_ipa_wlan_event_t type, uint8_t *mac_addr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005559{
5560 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07005561 qdf_ipa_msg_meta_t meta;
5562 qdf_ipa_wlan_msg_t *msg;
5563 qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005564 int ret;
5565
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005566 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: EVT: %s, MAC: %pM, sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005567 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5568 mac_addr, sta_id);
5569
5570 if (type >= IPA_WLAN_EVENT_MAX)
5571 return -EINVAL;
5572
5573 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5574 return -EINVAL;
5575
5576 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305577 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005578 return -EINVAL;
5579 }
5580
5581 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5582 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005583 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005584 return 0;
5585 }
5586
5587 /*
5588 * During IPA UC resource loading/unloading new events can be issued.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005589 */
Yun Park777d7242017-03-30 15:38:33 -07005590 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5591 (hdd_ipa->resource_loading || hdd_ipa->resource_unloading)) {
5592 unsigned int pending_event_count;
5593 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005594
Yun Park46255682017-10-09 15:56:34 -07005595 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park777d7242017-03-30 15:38:33 -07005596 "%s:IPA resource %s inprogress",
5597 hdd_ipa_wlan_event_to_str(type),
5598 hdd_ipa->resource_loading ?
5599 "load" : "unload");
5600
5601 /* Wait until completion of the long/unloading */
5602 ret = wait_for_completion_timeout(&hdd_ipa->ipa_resource_comp,
5603 msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME));
5604 if (!ret) {
5605 /*
5606 * If timed out, store the events separately and
5607 * handle them later.
5608 */
Yun Park46255682017-10-09 15:56:34 -07005609 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park777d7242017-03-30 15:38:33 -07005610 "IPA resource %s timed out",
5611 hdd_ipa->resource_loading ?
5612 "load" : "unload");
Yun Park7c4f31b2016-11-30 10:09:21 -08005613
Yun Parka4bb37c2017-12-08 16:14:22 -08005614 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005615
Yun Parka4bb37c2017-12-08 16:14:22 -08005616 pending_event_count =
5617 qdf_list_size(&hdd_ipa->pending_event);
5618 if (pending_event_count >=
5619 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
5620 hdd_debug("Reached max pending event count");
5621 qdf_list_remove_front(
5622 &hdd_ipa->pending_event,
5623 (qdf_list_node_t **)&pending_event);
5624 } else {
5625 pending_event =
5626 (struct ipa_uc_pending_event *)
5627 qdf_mem_malloc(sizeof(
Yun Park777d7242017-03-30 15:38:33 -07005628 struct ipa_uc_pending_event));
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005629 }
Yun Parka4bb37c2017-12-08 16:14:22 -08005630
5631 if (!pending_event) {
5632 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5633 "Pending event memory alloc fail");
5634 qdf_mutex_release(&hdd_ipa->ipa_lock);
5635 return -ENOMEM;
5636 }
5637
5638 pending_event->adapter = adapter;
5639 pending_event->sta_id = sta_id;
5640 pending_event->type = type;
5641 pending_event->is_loading =
5642 hdd_ipa->resource_loading;
5643 qdf_mem_copy(pending_event->mac_addr,
5644 mac_addr, QDF_MAC_ADDR_SIZE);
5645 qdf_list_insert_back(&hdd_ipa->pending_event,
5646 &pending_event->node);
5647
5648 qdf_mutex_release(&hdd_ipa->ipa_lock);
5649
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005650 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005651 }
Yun Park46255682017-10-09 15:56:34 -07005652 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Jeff Johnson4929cd92017-10-06 19:21:57 -07005653 "IPA resource %s completed",
5654 hdd_ipa->resource_loading ?
5655 "load" : "unload");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005656 }
5657
5658 hdd_ipa->stats.event[type]++;
5659
Yun Park6c86a662017-10-05 16:09:15 -07005660 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005661 switch (type) {
5662 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005663 qdf_mutex_acquire(&hdd_ipa->event_lock);
5664
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005665 /* STA already connected and without disconnect, connect again
5666 * This is Roaming scenario
5667 */
5668 if (hdd_ipa->sta_connected)
5669 hdd_ipa_cleanup_iface(adapter->ipa_context);
5670
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005671 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5672 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305673 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005674 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005675 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005676
Yun Park8f289c82016-10-18 16:38:21 -07005677 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5678 (hdd_ipa->sap_num_connected_sta > 0) &&
5679 !hdd_ipa->sta_connected) {
5680 qdf_mutex_release(&hdd_ipa->event_lock);
5681 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005682 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005683 qdf_mutex_acquire(&hdd_ipa->event_lock);
5684 }
5685
Jeff Johnson1b780e42017-10-31 14:11:45 -07005686 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005687 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005688 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005689
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005690 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005691
5692 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005693
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005694 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005695 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005696 break;
5697
5698 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005699 qdf_mutex_acquire(&hdd_ipa->event_lock);
5700
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005701 /* For DFS channel we get two start_bss event (before and after
5702 * CAC). Also when ACS range includes both DFS and non DFS
5703 * channels, we could possibly change channel many times due to
5704 * RADAR detection and chosen channel may not be a DFS channels.
5705 * So dont return error here. Just discard the event.
5706 */
Yun Park8f289c82016-10-18 16:38:21 -07005707 if (adapter->ipa_context) {
5708 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005709 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005710 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005711
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005712 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5713 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005714 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005715 hdd_err("%s: Evt: %d, Interface setup failed",
Yun Park6c86a662017-10-05 16:09:15 -07005716 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005717 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005718 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005719
Yun Park8f289c82016-10-18 16:38:21 -07005720 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5721 qdf_mutex_release(&hdd_ipa->event_lock);
5722 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005723 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005724 qdf_mutex_acquire(&hdd_ipa->event_lock);
5725 }
5726
Jeff Johnson1b780e42017-10-31 14:11:45 -07005727 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005728 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005729 (adapter->ipa_context))->iface_id;
5730
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305731 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005732 break;
5733
5734 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305735 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005736
5737 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005738 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005739 hdd_err("%s: Evt: %d, STA already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005740 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005741 return -EINVAL;
5742 }
Yun Parka37592b2016-06-11 17:10:28 -07005743
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005744 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005745
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005746 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005747 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005748 msg_ex->name);
5749 } else {
5750 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Park3b7152b2017-08-25 08:33:37 -07005751 if ((1 == hdd_ipa->num_iface) &&
Yun Parka37592b2016-06-11 17:10:28 -07005752 (HDD_IPA_UC_NUM_WDI_PIPE ==
Yun Park3b7152b2017-08-25 08:33:37 -07005753 hdd_ipa->activated_fw_pipe) &&
5754 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005755 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005756 }
5757
Yun Park74127cf2016-09-18 11:22:41 -07005758 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5759 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005760 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005761 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005762 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005763 qdf_mutex_acquire(&hdd_ipa->event_lock);
Jeff Johnson1b780e42017-10-31 14:11:45 -07005764 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005765 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005766 }
5767
Yun Park8f289c82016-10-18 16:38:21 -07005768 hdd_ipa_cleanup_iface(adapter->ipa_context);
5769
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305770 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005771
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005772 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005773 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005774 break;
5775
5776 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005777 qdf_mutex_acquire(&hdd_ipa->event_lock);
5778
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005779 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005780 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005781 hdd_err("%s: Evt: %d, SAP already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005782 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005783 return -EINVAL;
5784 }
5785
Yun Park3b7152b2017-08-25 08:33:37 -07005786 if ((1 == hdd_ipa->num_iface) &&
5787 (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
5788 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005789 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005790 /*
5791 * We disable WDI pipes directly here since
5792 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5793 * processed when unloading WLAN driver is in
5794 * progress
5795 */
5796 hdd_ipa_uc_disable_pipes(hdd_ipa);
5797 } else {
Yun Park199c2ed2017-10-02 11:24:22 -07005798 /*
5799 * This shouldn't happen :
5800 * No interface left but WDI pipes are still
5801 * active - force close WDI pipes
5802 */
5803 WARN_ON(1);
5804 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
5805 "No interface left but WDI pipes are still active - force close WDI pipes");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005806 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5807 }
5808 }
5809
5810 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005811 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005812 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005813 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005814 qdf_mutex_acquire(&hdd_ipa->event_lock);
Jeff Johnson1b780e42017-10-31 14:11:45 -07005815 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005816 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005817 }
Yun Parka37592b2016-06-11 17:10:28 -07005818
Yun Park8f289c82016-10-18 16:38:21 -07005819 hdd_ipa_cleanup_iface(adapter->ipa_context);
5820
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305821 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005822 break;
5823
5824 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005825 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005826 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005827 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305828 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005829 return 0;
5830 }
5831
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305832 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005833 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5834 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005835 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305836 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005837 "%s: STA ID %d found, not valid",
5838 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005839 return 0;
5840 }
Yun Park312f71a2015-12-08 10:22:42 -08005841
5842 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005843 if (hdd_ipa->sap_num_connected_sta == 0 &&
5844 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005845 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005846 hdd_ipa->sta_connected) {
5847 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005848 hdd_ipa_uc_offload_enable_disable(
5849 hdd_get_adapter(hdd_ipa->hdd_ctx,
5850 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005851 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005852 qdf_mutex_acquire(&hdd_ipa->event_lock);
5853 }
Yun Parka37592b2016-06-11 17:10:28 -07005854
Yun Park312f71a2015-12-08 10:22:42 -08005855 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5856 if (ret) {
Yun Park46255682017-10-09 15:56:34 -07005857 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park312f71a2015-12-08 10:22:42 -08005858 "%s: handle 1st con ret %d",
5859 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005860
5861 if (hdd_ipa_uc_sta_is_enabled(
5862 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005863 hdd_ipa->sta_connected) {
5864 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005865 hdd_ipa_uc_offload_enable_disable(
5866 hdd_get_adapter(
5867 hdd_ipa->hdd_ctx,
5868 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005869 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005870 } else {
5871 qdf_mutex_release(&hdd_ipa->event_lock);
5872 }
Yun Parka37592b2016-06-11 17:10:28 -07005873
Yun Park312f71a2015-12-08 10:22:42 -08005874 return ret;
5875 }
5876 }
5877
5878 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005879
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305880 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005881
Yun Park6c86a662017-10-05 16:09:15 -07005882 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
5883 QDF_IPA_MSG_META_MSG_LEN(&meta) =
5884 (sizeof(qdf_ipa_wlan_msg_ex_t) +
5885 sizeof(qdf_ipa_wlan_hdr_attrib_val_t));
5886 msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005887
5888 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305889 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005890 "msg_ex allocation failed");
5891 return -ENOMEM;
5892 }
5893 strlcpy(msg_ex->name, adapter->dev->name,
5894 IPA_RESOURCE_NAME_MAX);
5895 msg_ex->num_of_attribs = 1;
5896 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5897 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5898 msg_ex->attribs[0].offset =
5899 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5900 } else {
5901 msg_ex->attribs[0].offset =
5902 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5903 }
5904 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5905 IPA_MAC_ADDR_SIZE);
5906
Yun Park84c0ceb2018-01-11 10:37:10 -08005907 ret = qdf_ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005908
5909 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005910 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305911 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305912 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005913 return ret;
5914 }
5915 hdd_ipa->stats.num_send_msg++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005916
Yun Park199c2ed2017-10-02 11:24:22 -07005917 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005918 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005919 return ret;
5920
5921 case WLAN_CLIENT_DISCONNECT:
5922 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005923 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005924 "%s: IPA UC OFFLOAD NOT ENABLED",
5925 msg_ex->name);
5926 return 0;
5927 }
5928
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305929 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Park73ea8bb2017-08-25 07:27:39 -07005930 if (!hdd_ipa->sap_num_connected_sta) {
5931 qdf_mutex_release(&hdd_ipa->event_lock);
5932 hdd_err("%s: Evt: %d, Client already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005933 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Yun Park73ea8bb2017-08-25 07:27:39 -07005934 return 0;
5935 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005936 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005937 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305938 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005939 "%s: STA ID %d NOT found, not valid",
5940 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005941 return 0;
5942 }
5943 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005944
Yun Park9b5030f2016-11-08 12:02:37 -08005945 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005946 if (!hdd_ipa->sap_num_connected_sta &&
5947 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005948 if ((false == hdd_ipa->resource_unloading)
5949 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305950 hdd_ipa->activated_fw_pipe) &&
5951 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005952 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5953 }
5954
Yun Park9b5030f2016-11-08 12:02:37 -08005955 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jiad9d472c92017-07-28 14:05:31 +08005956 hdd_ipa->sta_connected) {
5957 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005958 hdd_ipa_uc_offload_enable_disable(
5959 hdd_get_adapter(hdd_ipa->hdd_ctx,
5960 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005961 SIR_STA_RX_DATA_OFFLOAD, false);
jiad9d472c92017-07-28 14:05:31 +08005962 } else {
5963 qdf_mutex_release(&hdd_ipa->event_lock);
5964 }
Yun Park8f289c82016-10-18 16:38:21 -07005965 } else {
5966 qdf_mutex_release(&hdd_ipa->event_lock);
5967 }
Yun Parkfec73dc2017-09-06 10:40:07 -07005968
Yun Park199c2ed2017-10-02 11:24:22 -07005969 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005970 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005971 break;
5972
5973 default:
5974 return 0;
5975 }
5976
Yun Park6c86a662017-10-05 16:09:15 -07005977 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
5978 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005979 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305980 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005981 return -ENOMEM;
5982 }
5983
Yun Park6c86a662017-10-05 16:09:15 -07005984 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
5985 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), adapter->dev->name,
5986 IPA_RESOURCE_NAME_MAX);
5987 memcpy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, ETH_ALEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005988
Srinivas Girigowda97852372017-03-06 16:52:59 -08005989 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Yun Park6c86a662017-10-05 16:09:15 -07005990 QDF_IPA_WLAN_MSG_NAME(msg),
5991 QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005992
Yun Park84c0ceb2018-01-11 10:37:10 -08005993 ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005994
5995 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005996 hdd_err("%s: Evt: %d fail:%d",
Yun Park6c86a662017-10-05 16:09:15 -07005997 QDF_IPA_WLAN_MSG_NAME(msg),
5998 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305999 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006000 return ret;
6001 }
6002
6003 hdd_ipa->stats.num_send_msg++;
6004
6005end:
6006 return ret;
6007}
6008
6009/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006010 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07006011 * @adapter: adapter upon which the event was received
6012 * @sta_id: station id for the event
6013 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
6014 * @mac_address: MAC address associated with the event
6015 *
6016 * This function is meant to be called from outside of wlan_hdd_ipa.c.
6017 *
6018 * Return: 0 on success, negative errno value on error
6019 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07006020int hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Mohit Khannafa99aea2016-05-12 21:43:13 -07006021 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
6022{
Yun Park6c86a662017-10-05 16:09:15 -07006023 qdf_ipa_wlan_event_t type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006024 int ret = 0;
6025
6026 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07006027
Leo Changa202b522016-10-14 16:13:50 -07006028 /* Data path offload only support for STA and SAP mode */
6029 if ((QDF_STA_MODE == adapter->device_mode) ||
6030 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006031 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07006032
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006033 cds_ssr_unprotect(__func__);
6034
6035 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07006036}
6037
6038/**
6039 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
6040 * @hdd_ipa: Global HDD IPA context
Yun Parka4bb37c2017-12-08 16:14:22 -08006041 * @is_loading: Indicate if invoked during loading
Mohit Khannafa99aea2016-05-12 21:43:13 -07006042 *
6043 * Return: None
6044 */
6045static void
Yun Parka4bb37c2017-12-08 16:14:22 -08006046hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa, bool is_loading)
Mohit Khannafa99aea2016-05-12 21:43:13 -07006047{
6048 unsigned int pending_event_count;
6049 struct ipa_uc_pending_event *pending_event = NULL;
6050
6051 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08006052 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07006053 "Pending Event Count %d", pending_event_count);
Mohit Khannafa99aea2016-05-12 21:43:13 -07006054 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08006055 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07006056 "No Pending Event");
Mohit Khannafa99aea2016-05-12 21:43:13 -07006057 return;
6058 }
6059
6060 qdf_list_remove_front(&hdd_ipa->pending_event,
6061 (qdf_list_node_t **)&pending_event);
6062 while (pending_event != NULL) {
Yun Parka4bb37c2017-12-08 16:14:22 -08006063 if (pending_event->is_loading == is_loading)
6064 __hdd_ipa_wlan_evt(pending_event->adapter,
6065 pending_event->sta_id,
6066 pending_event->type,
6067 pending_event->mac_addr);
Mohit Khannafa99aea2016-05-12 21:43:13 -07006068 qdf_mem_free(pending_event);
6069 pending_event = NULL;
6070 qdf_list_remove_front(&hdd_ipa->pending_event,
6071 (qdf_list_node_t **)&pending_event);
6072 }
6073}
6074
6075/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006076 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
6077 * @state: IPA RM state value
6078 *
6079 * Return: ASCII string representing the IPA RM state
6080 */
6081static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
6082{
6083 switch (state) {
6084 case HDD_IPA_RM_RELEASED:
6085 return "RELEASED";
6086 case HDD_IPA_RM_GRANT_PENDING:
6087 return "GRANT_PENDING";
6088 case HDD_IPA_RM_GRANTED:
6089 return "GRANTED";
6090 }
6091
6092 return "UNKNOWN";
6093}
6094
6095/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006096 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006097 * @hdd_ctx: HDD global context
6098 *
6099 * Allocate hdd_ipa resources, ipa pipe resource and register
6100 * wlan interface with IPA module.
6101 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306102 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006103 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07006104static QDF_STATUS __hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006105{
6106 struct hdd_ipa_priv *hdd_ipa = NULL;
6107 int ret, i;
6108 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08006109 struct ol_txrx_pdev_t *pdev = NULL;
Yun Park84c0ceb2018-01-11 10:37:10 -08006110 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006111
6112 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306113 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006114
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08006115 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Park199c2ed2017-10-02 11:24:22 -07006116
Yun Parkbaa62862017-01-18 13:43:34 -08006117 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07006118 if (!pdev) {
6119 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
6120 goto fail_return;
6121 }
6122
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306123 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006124 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05306125 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08006126 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006127 }
6128
6129 hdd_ctx->hdd_ipa = hdd_ipa;
6130 ghdd_ipa = hdd_ipa;
6131 hdd_ipa->hdd_ctx = hdd_ctx;
6132 hdd_ipa->num_iface = 0;
6133
Yun Park84c0ceb2018-01-11 10:37:10 -08006134 hdd_ipa_wdi_get_wdi_version(hdd_ipa);
6135
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006136 /* Create the interface context */
6137 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6138 iface_context = &hdd_ipa->iface_context[i];
6139 iface_context->hdd_ipa = hdd_ipa;
6140 iface_context->cons_client =
6141 hdd_ipa_adapter_2_client[i].cons_client;
6142 iface_context->prod_client =
6143 hdd_ipa_adapter_2_client[i].prod_client;
6144 iface_context->iface_id = i;
6145 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306146 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08006147 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006148
Leo Chang69c39692016-10-12 20:11:12 -07006149 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306150 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006151 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05306152 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08006153 qdf_list_create(&hdd_ipa->pending_event, 1000);
6154 qdf_mutex_create(&hdd_ipa->event_lock);
6155 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006156
Yun Park84c0ceb2018-01-11 10:37:10 -08006157 ret = hdd_ipa_wdi_setup_rm(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006158 if (ret)
6159 goto fail_setup_rm;
6160
Yun Park9281cb72017-11-30 11:14:30 -08006161 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++)
6162 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
6163 sizeof(struct hdd_ipa_sys_pipe));
6164
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006165 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
6166 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306167 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006168 hdd_ipa->sap_num_connected_sta = 0;
6169 hdd_ipa->ipa_tx_packets_diff = 0;
6170 hdd_ipa->ipa_rx_packets_diff = 0;
6171 hdd_ipa->ipa_p_tx_packets = 0;
6172 hdd_ipa->ipa_p_rx_packets = 0;
6173 hdd_ipa->resource_loading = false;
6174 hdd_ipa->resource_unloading = false;
6175 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07006176 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08006177 hdd_ipa->wdi_enabled = false;
Yun Park9281cb72017-11-30 11:14:30 -08006178 /* Setup IPA system pipes */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006179 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
6180 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6181 if (ret)
6182 goto fail_create_sys_pipe;
6183 }
Yun Park84c0ceb2018-01-11 10:37:10 -08006184
6185 ret = hdd_ipa_wdi_init(hdd_ipa);
6186 if (ret) {
6187 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
6188 "IPA WDI init failed: ret=%d", ret);
6189 if (ret == -EACCES)
6190 ret = hdd_ipa_uc_send_wdi_control_msg(false);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08006191 goto fail_create_sys_pipe;
Yun Park84c0ceb2018-01-11 10:37:10 -08006192 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006193 } else {
6194 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
6195 if (ret)
6196 goto fail_create_sys_pipe;
6197 }
6198
Yun Park66f24c42017-03-20 10:39:47 -07006199 /* When IPA clock scaling is disabled, initialze maximum clock */
6200 if (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)) {
Yun Park66f24c42017-03-20 10:39:47 -07006201 hdd_debug("IPA clock scaling is disabled.");
6202 hdd_debug("Set initial CONS/PROD perf: %d",
Yun Park84c0ceb2018-01-11 10:37:10 -08006203 HDD_IPA_MAX_BANDWIDTH);
6204 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS,
6205 HDD_IPA_MAX_BANDWIDTH);
Yun Park66f24c42017-03-20 10:39:47 -07006206 if (ret) {
6207 hdd_err("RM CONS set perf profile failed: %d", ret);
6208 goto fail_create_sys_pipe;
6209 }
6210
Yun Park84c0ceb2018-01-11 10:37:10 -08006211 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD,
6212 HDD_IPA_MAX_BANDWIDTH);
Yun Park66f24c42017-03-20 10:39:47 -07006213 if (ret) {
6214 hdd_err("RM PROD set perf profile failed: %d", ret);
6215 goto fail_create_sys_pipe;
6216 }
6217 }
6218
Yun Park777d7242017-03-30 15:38:33 -07006219 init_completion(&hdd_ipa->ipa_resource_comp);
6220
Yun Parke4239802018-01-09 11:01:40 -08006221 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306222 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006223
6224fail_create_sys_pipe:
Yun Park84c0ceb2018-01-11 10:37:10 -08006225 hdd_ipa_wdi_destroy_rm(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006226fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306227 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306228 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08006229 hdd_ctx->hdd_ipa = NULL;
6230 ghdd_ipa = NULL;
6231fail_return:
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08006232 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: fail");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306233 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006234}
6235
6236/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006237 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
6238 * @hdd_ctx: HDD global context
6239 *
6240 * Allocate hdd_ipa resources, ipa pipe resource and register
6241 * wlan interface with IPA module.
6242 *
6243 * Return: QDF_STATUS enumeration
6244 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07006245QDF_STATUS hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006246{
6247 QDF_STATUS ret;
6248
6249 cds_ssr_protect(__func__);
6250 ret = __hdd_ipa_init(hdd_ctx);
6251 cds_ssr_unprotect(__func__);
6252
6253 return ret;
6254}
6255
Arun Khandavallicc544b32017-01-30 19:52:16 +05306256
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006257/**
Govind Singh1dab23b2017-08-12 13:31:00 +05306258 * __hdd_ipa_flush - flush IPA exception path SKB's
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006259 * @hdd_ctx: HDD global context
6260 *
Govind Singh1dab23b2017-08-12 13:31:00 +05306261 * Return: none
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006262 */
Govind Singh1dab23b2017-08-12 13:31:00 +05306263static void __hdd_ipa_flush(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006264{
6265 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
Nirav Shahcbc6d722016-03-01 16:24:53 +05306266 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006267 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
6268
6269 if (!hdd_ipa_is_enabled(hdd_ctx))
Govind Singh1dab23b2017-08-12 13:31:00 +05306270 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006271
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006272 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006273
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306274 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006275
Nirav Shahcbc6d722016-03-01 16:24:53 +05306276 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
6277 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306278 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006279
6280 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07006281 if (pm_tx_cb->ipa_tx_desc)
6282 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006283
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306284 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006285 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306286 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Govind Singh1dab23b2017-08-12 13:31:00 +05306287}
6288
6289/**
6290 * __hdd_ipa_cleanup - IPA cleanup function
6291 * @hdd_ctx: HDD global context
6292 *
6293 * Return: QDF_STATUS enumeration
6294 */
6295static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
6296{
6297 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
6298 int i;
6299 struct hdd_ipa_iface_context *iface_context = NULL;
6300
6301 if (!hdd_ipa_is_enabled(hdd_ctx))
6302 return QDF_STATUS_SUCCESS;
6303
6304 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
6305 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
6306 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6307 }
6308
6309 /* Teardown IPA sys_pipe for MCC */
6310 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
6311 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6312
Yun Park84c0ceb2018-01-11 10:37:10 -08006313 hdd_ipa_wdi_destroy_rm(hdd_ipa);
Govind Singh1dab23b2017-08-12 13:31:00 +05306314
6315 __hdd_ipa_flush(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006316
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306317 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006318 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006319
6320 /* destory the interface lock */
6321 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6322 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306323 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006324 }
6325
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006326 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park84c0ceb2018-01-11 10:37:10 -08006327 hdd_ipa_wdi_cleanup();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006328 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306329 qdf_mutex_destroy(&hdd_ipa->event_lock);
6330 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07006331 qdf_list_destroy(&hdd_ipa->pending_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006332
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006333 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6334 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
Yun Park6edb2172018-01-14 00:18:05 -08006335 qdf_mem_free(hdd_ipa->uc_op_work[i].msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006336 hdd_ipa->uc_op_work[i].msg = NULL;
6337 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006338 }
6339
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306340 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006341 hdd_ctx->hdd_ipa = NULL;
6342
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306343 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006344}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006345
6346/**
Govind Singh1dab23b2017-08-12 13:31:00 +05306347 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_flush
6348 * @hdd_ctx: HDD global context
6349 *
6350 * Return: None
6351 */
6352void hdd_ipa_flush(struct hdd_context *hdd_ctx)
6353{
6354 cds_ssr_protect(__func__);
6355 __hdd_ipa_flush(hdd_ctx);
6356 cds_ssr_unprotect(__func__);
6357}
6358
6359/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006360 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
6361 * @hdd_ctx: HDD global context
6362 *
6363 * Return: QDF_STATUS enumeration
6364 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07006365QDF_STATUS hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006366{
6367 QDF_STATUS ret;
6368
6369 cds_ssr_protect(__func__);
6370 ret = __hdd_ipa_cleanup(hdd_ctx);
6371 cds_ssr_unprotect(__func__);
6372
6373 return ret;
6374}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006375#endif /* IPA_OFFLOAD */