blob: 48c67d6f97bc976b5007e9c022a1c25397ef470d [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 Park6c86a662017-10-05 16:09:15 -070038#include <qdf_ipa.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039#include <wlan_hdd_includes.h>
40#include <wlan_hdd_ipa.h>
41
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080042#include <linux/inetdevice.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080043#include <wlan_hdd_softap_tx_rx.h>
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +053044#include <ol_txrx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070045#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080046
47#include "cds_sched.h"
48
49#include "wma.h"
50#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080051#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080052
Dhanashri Atreb08959a2016-03-01 17:28:03 -080053#include "cdp_txrx_ipa.h"
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -080054#include "wlan_policy_mgr_api.h"
55
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080056#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080057#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
Yun Parkb4f591d2017-03-29 15:51:01 -070058
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059#define HDD_IPA_UC_NUM_WDI_PIPE 2
60#define HDD_IPA_UC_MAX_PENDING_EVENT 33
61
62#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
63#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
64#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
65#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
66
67#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
68#define HDD_IPA_MAX_IFACE 3
69#define HDD_IPA_MAX_SYSBAM_PIPE 4
Yun Parkb4f591d2017-03-29 15:51:01 -070070
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
72#define HDD_IPA_ENABLE_MASK BIT(0)
73#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
74#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
75#define HDD_IPA_RM_ENABLE_MASK BIT(3)
76#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
77#define HDD_IPA_UC_ENABLE_MASK BIT(5)
78#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
79#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
80
Yun Parkf19e07d2015-11-20 11:34:27 -080081#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
82
tfyu0380a972017-07-13 18:19:37 +080083#define IPA_WLAN_RX_SOFTIRQ_THRESH 16
84
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -070085enum hdd_ipa_uc_op_code {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080086 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
87 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
88 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
89 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
90 HDD_IPA_UC_OPCODE_STATS = 4,
Yun Park637d6482016-10-05 10:51:33 -070091#ifdef FEATURE_METERING
92 HDD_IPA_UC_OPCODE_SHARING_STATS = 5,
93 HDD_IPA_UC_OPCODE_QUOTA_RSP = 6,
94 HDD_IPA_UC_OPCODE_QUOTA_IND = 7,
95#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -080096 HDD_IPA_UC_OPCODE_UC_READY = 8,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080097 /* keep this last */
98 HDD_IPA_UC_OPCODE_MAX
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -070099};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800100
101/**
102 * enum - Reason codes for stat query
103 *
104 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
105 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
106 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
Yun Parkb187d542016-11-14 18:10:04 -0800107 * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800108 */
109enum {
110 HDD_IPA_UC_STAT_REASON_NONE,
111 HDD_IPA_UC_STAT_REASON_DEBUG,
Yun Park46255682017-10-09 15:56:34 -0700112 HDD_IPA_UC_STAT_REASON_BW_CAL
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800113};
114
115/**
116 * enum hdd_ipa_rm_state - IPA resource manager state
117 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
118 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
119 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
120 */
121enum hdd_ipa_rm_state {
122 HDD_IPA_RM_RELEASED,
123 HDD_IPA_RM_GRANT_PENDING,
124 HDD_IPA_RM_GRANTED,
125};
126
127struct llc_snap_hdr {
128 uint8_t dsap;
129 uint8_t ssap;
130 uint8_t resv[4];
131 __be16 eth_type;
132} __packed;
133
Leo Chang3bc8fed2015-11-13 10:59:47 -0800134/**
135 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
136 * @eth: ether II header
137 * @llc_snap: LLC snap header
138 *
139 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140struct hdd_ipa_tx_hdr {
141 struct ethhdr eth;
142 struct llc_snap_hdr llc_snap;
143} __packed;
144
Leo Chang3bc8fed2015-11-13 10:59:47 -0800145/**
146 * struct frag_header - fragment header type registered to IPA hardware
147 * @length: fragment length
148 * @reserved1: Reserved not used
149 * @reserved2: Reserved not used
150 *
151 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800152struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800153 uint16_t length;
154 uint32_t reserved1;
155 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800156} __packed;
157
Leo Chang3bc8fed2015-11-13 10:59:47 -0800158/**
159 * struct ipa_header - ipa header type registered to IPA hardware
160 * @vdev_id: vdev id
161 * @reserved: Reserved not used
162 *
163 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164struct ipa_header {
165 uint32_t
166 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
167 reserved:24;
168} __packed;
169
Leo Chang3bc8fed2015-11-13 10:59:47 -0800170/**
171 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
172 * @frag_hd: fragment header
173 * @ipa_hd: ipa header
174 * @eth: ether II header
175 *
176 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800177struct hdd_ipa_uc_tx_hdr {
178 struct frag_header frag_hd;
179 struct ipa_header ipa_hd;
180 struct ethhdr eth;
181} __packed;
182
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800183/**
184 * struct hdd_ipa_cld_hdr - IPA CLD Header
185 * @reserved: reserved fields
186 * @iface_id: interface ID
187 * @sta_id: Station ID
188 *
189 * Packed 32-bit structure
190 * +----------+----------+--------------+--------+
191 * | Reserved | QCMAP ID | interface id | STA ID |
192 * +----------+----------+--------------+--------+
193 */
194struct hdd_ipa_cld_hdr {
195 uint8_t reserved[2];
196 uint8_t iface_id;
197 uint8_t sta_id;
198} __packed;
199
200struct hdd_ipa_rx_hdr {
201 struct hdd_ipa_cld_hdr cld_hdr;
202 struct ethhdr eth;
203} __packed;
204
205struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700206 bool exception;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700207 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800208 struct hdd_ipa_iface_context *iface_context;
Yun Park6c86a662017-10-05 16:09:15 -0700209 qdf_ipa_rx_data_t *ipa_tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800210};
211
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800212struct hdd_ipa_sys_pipe {
213 uint32_t conn_hdl;
214 uint8_t conn_hdl_valid;
Yun Park6c86a662017-10-05 16:09:15 -0700215 qdf_ipa_sys_connect_params_t ipa_sys_params;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216};
217
218struct hdd_ipa_iface_stats {
219 uint64_t num_tx;
220 uint64_t num_tx_drop;
221 uint64_t num_tx_err;
222 uint64_t num_tx_cac_drop;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 uint64_t num_rx_ipa_excep;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800224};
225
226struct hdd_ipa_priv;
227
228struct hdd_ipa_iface_context {
229 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700230 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800231 void *tl_context;
232
Yun Park6c86a662017-10-05 16:09:15 -0700233 qdf_ipa_client_type_t cons_client;
234 qdf_ipa_client_type_t prod_client;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800235
236 uint8_t iface_id; /* This iface ID */
237 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530238 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800239 uint32_t ifa_address;
240 struct hdd_ipa_iface_stats stats;
241};
242
243struct hdd_ipa_stats {
244 uint32_t event[IPA_WLAN_EVENT_MAX];
245 uint64_t num_send_msg;
246 uint64_t num_free_msg;
247
248 uint64_t num_rm_grant;
249 uint64_t num_rm_release;
250 uint64_t num_rm_grant_imm;
251 uint64_t num_cons_perf_req;
252 uint64_t num_prod_perf_req;
253
254 uint64_t num_rx_drop;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800255
Yun Park52b2b992016-09-22 15:49:51 -0700256 uint64_t num_tx_desc_q_cnt;
257 uint64_t num_tx_desc_error;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800258 uint64_t num_tx_comp_cnt;
259 uint64_t num_tx_queued;
260 uint64_t num_tx_dequeued;
261 uint64_t num_max_pm_queue;
262
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800263 uint64_t num_rx_excep;
Yun Parkb187d542016-11-14 18:10:04 -0800264 uint64_t num_tx_fwd_ok;
265 uint64_t num_tx_fwd_err;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800266};
267
268struct ipa_uc_stas_map {
269 bool is_reserved;
270 uint8_t sta_id;
271};
272struct op_msg_type {
273 uint8_t msg_t;
274 uint8_t rsvd;
275 uint16_t op_code;
276 uint16_t len;
277 uint16_t rsvd_snd;
278};
279
280struct ipa_uc_fw_stats {
281 uint32_t tx_comp_ring_base;
282 uint32_t tx_comp_ring_size;
283 uint32_t tx_comp_ring_dbell_addr;
284 uint32_t tx_comp_ring_dbell_ind_val;
285 uint32_t tx_comp_ring_dbell_cached_val;
286 uint32_t tx_pkts_enqueued;
287 uint32_t tx_pkts_completed;
288 uint32_t tx_is_suspend;
289 uint32_t tx_reserved;
290 uint32_t rx_ind_ring_base;
291 uint32_t rx_ind_ring_size;
292 uint32_t rx_ind_ring_dbell_addr;
293 uint32_t rx_ind_ring_dbell_ind_val;
294 uint32_t rx_ind_ring_dbell_ind_cached_val;
295 uint32_t rx_ind_ring_rdidx_addr;
296 uint32_t rx_ind_ring_rd_idx_cached_val;
297 uint32_t rx_refill_idx;
298 uint32_t rx_num_pkts_indicated;
299 uint32_t rx_buf_refilled;
300 uint32_t rx_num_ind_drop_no_space;
301 uint32_t rx_num_ind_drop_no_buf;
302 uint32_t rx_is_suspend;
303 uint32_t rx_reserved;
304};
305
306struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530307 qdf_list_node_t node;
Jeff Johnson49d45e62017-08-29 14:30:42 -0700308 struct hdd_adapter *adapter;
Yun Park6c86a662017-10-05 16:09:15 -0700309 qdf_ipa_wlan_event_t type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800310 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530311 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Yun Parka4bb37c2017-12-08 16:14:22 -0800312 bool is_loading;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800313};
314
315/**
316 * struct uc_rm_work_struct
317 * @work: uC RM work
318 * @event: IPA RM event
319 */
320struct uc_rm_work_struct {
321 struct work_struct work;
Yun Park6c86a662017-10-05 16:09:15 -0700322 qdf_ipa_rm_event_t event;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800323};
324
325/**
326 * struct uc_op_work_struct
327 * @work: uC OP work
328 * @msg: OP message
329 */
330struct uc_op_work_struct {
331 struct work_struct work;
332 struct op_msg_type *msg;
333};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800334
335/**
336 * struct uc_rt_debug_info
337 * @time: system time
338 * @ipa_excep_count: IPA exception packet count
339 * @rx_drop_count: IPA Rx drop packet count
340 * @net_sent_count: IPA Rx packet sent to network stack count
341 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800342 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800343 * @tx_fwd_count: IPA Tx forward packet count
344 * @rx_destructor_call: IPA Rx packet destructor count
345 */
346struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530347 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800348 uint64_t ipa_excep_count;
349 uint64_t rx_drop_count;
350 uint64_t net_sent_count;
351 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800352 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800353 uint64_t tx_fwd_count;
354 uint64_t rx_destructor_call;
355};
356
Yun Park637d6482016-10-05 10:51:33 -0700357#ifdef FEATURE_METERING
358struct ipa_uc_sharing_stats {
359 uint64_t ipv4_rx_packets;
360 uint64_t ipv4_rx_bytes;
361 uint64_t ipv6_rx_packets;
362 uint64_t ipv6_rx_bytes;
363 uint64_t ipv4_tx_packets;
364 uint64_t ipv4_tx_bytes;
365 uint64_t ipv6_tx_packets;
366 uint64_t ipv6_tx_bytes;
367};
368
369struct ipa_uc_quota_rsp {
370 uint8_t success;
371 uint8_t reserved[3];
372 uint32_t quota_lo; /* quota limit low bytes */
373 uint32_t quota_hi; /* quota limit high bytes */
374};
375
376struct ipa_uc_quota_ind {
377 uint64_t quota_bytes; /* quota limit in bytes */
378};
379#endif
380
Yun Park52b2b992016-09-22 15:49:51 -0700381/**
382 * struct hdd_ipa_tx_desc
383 * @link: link to list head
384 * @priv: pointer to priv list entry
385 * @id: Tx desc idex
386 * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor
387 */
388struct hdd_ipa_tx_desc {
389 struct list_head link;
390 void *priv;
391 uint32_t id;
Yun Park6c86a662017-10-05 16:09:15 -0700392 qdf_ipa_rx_data_t *ipa_tx_desc_ptr;
Yun Park52b2b992016-09-22 15:49:51 -0700393};
394
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800395struct hdd_ipa_priv {
396 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
397 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
398 uint8_t num_iface;
399 enum hdd_ipa_rm_state rm_state;
400 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530401 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800402 * APIs as it is taken care gracefully. Without this, kernel would throw
403 * an warning if spin_lock_bh is used while IRQ is disabled
404 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530405 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800406 struct uc_rm_work_struct uc_rm_work;
407 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530408 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800409 struct delayed_work wake_lock_work;
410 bool wake_lock_released;
411
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800412 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530413 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800414 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530415 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800416 bool suspended;
417
Yun Park52b2b992016-09-22 15:49:51 -0700418 qdf_spinlock_t q_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800419
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800420 struct list_head pend_desc_head;
Yun Park52b2b992016-09-22 15:49:51 -0700421 struct hdd_ipa_tx_desc *tx_desc_list;
422 struct list_head free_tx_desc_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700424 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800425 struct hdd_ipa_stats stats;
426
427 struct notifier_block ipv4_notifier;
428 uint32_t curr_prod_bw;
429 uint32_t curr_cons_bw;
430
431 uint8_t activated_fw_pipe;
432 uint8_t sap_num_connected_sta;
433 uint8_t sta_connected;
434 uint32_t tx_pipe_handle;
435 uint32_t rx_pipe_handle;
436 bool resource_loading;
437 bool resource_unloading;
438 bool pending_cons_req;
439 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530440 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530441 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700442 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800443 uint32_t ipa_tx_packets_diff;
444 uint32_t ipa_rx_packets_diff;
445 uint32_t ipa_p_tx_packets;
446 uint32_t ipa_p_rx_packets;
447 uint32_t stat_req_reason;
448 uint64_t ipa_tx_forward;
449 uint64_t ipa_rx_discard;
450 uint64_t ipa_rx_net_send_count;
Yun Park46255682017-10-09 15:56:34 -0700451 uint64_t ipa_rx_internal_drop_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800452 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530453 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800454 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
455 unsigned int rt_buf_fill_index;
Yun Park6c86a662017-10-05 16:09:15 -0700456 qdf_ipa_wdi_in_params_t cons_pipe_in;
457 qdf_ipa_wdi_in_params_t prod_pipe_in;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800458 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800459 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530460 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530461 qdf_mutex_t rt_debug_lock;
462 qdf_mutex_t ipa_lock;
Yun Parkb4f591d2017-03-29 15:51:01 -0700463
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800464 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
465 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Yun Park637d6482016-10-05 10:51:33 -0700466#ifdef FEATURE_METERING
467 struct ipa_uc_sharing_stats ipa_sharing_stats;
468 struct ipa_uc_quota_rsp ipa_quota_rsp;
469 struct ipa_uc_quota_ind ipa_quota_ind;
470 struct completion ipa_uc_sharing_stats_comp;
471 struct completion ipa_uc_set_quota_comp;
472#endif
Yun Park777d7242017-03-30 15:38:33 -0700473 struct completion ipa_resource_comp;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474};
475
Leo Changcc923e22016-06-16 15:29:03 -0700476#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
477#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800478#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
479#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
480#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
481#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
482#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700483#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
484 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800485
486#define HDD_IPA_GET_IFACE_ID(_data) \
487 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
488
489#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530490 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800491 "%s:%d: "fmt, __func__, __LINE__, ## args)
492
Govind Singhb6a89772016-08-12 11:23:35 +0530493#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
494 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
495 "%s:%d: "fmt, __func__, __LINE__, ## args)
496
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800497#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
498 do { \
Yun Parkec845302016-12-15 09:22:57 -0800499 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \
500 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501 } while (0)
502
503#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
504 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
505
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800506#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
507
Yun Park0dad1002017-07-14 14:57:01 -0700508#define HDD_IPA_DBG_DUMP_RX_LEN 84
Yun Parkb187d542016-11-14 18:10:04 -0800509#define HDD_IPA_DBG_DUMP_TX_LEN 48
510
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800511static struct hdd_ipa_adapter_2_client {
Yun Park6c86a662017-10-05 16:09:15 -0700512 qdf_ipa_client_type_t cons_client;
513 qdf_ipa_client_type_t prod_client;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800514} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
515 {
516 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
517 }, {
518 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
519 }, {
520 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
521 },
522};
523
Yun Park637d6482016-10-05 10:51:33 -0700524#ifdef FEATURE_METERING
525#define IPA_UC_SHARING_STATES_WAIT_TIME 500
526#define IPA_UC_SET_QUOTA_WAIT_TIME 500
527#endif
528
Yun Park777d7242017-03-30 15:38:33 -0700529#define IPA_RESOURCE_COMP_WAIT_TIME 100
530
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800531static struct hdd_ipa_priv *ghdd_ipa;
532
533/* Local Function Prototypes */
Yun Park6c86a662017-10-05 16:09:15 -0700534static void hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800535 unsigned long data);
Yun Park6c86a662017-10-05 16:09:15 -0700536static void hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800537 unsigned long data);
Yun Parkb4f591d2017-03-29 15:51:01 -0700538#ifdef FEATURE_METERING
Yun Park6c86a662017-10-05 16:09:15 -0700539static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Parkb4f591d2017-03-29 15:51:01 -0700540 void *data);
541#else
542static void hdd_ipa_wdi_meter_notifier_cb(void);
543#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800544static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545
546static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Yun Parka4bb37c2017-12-08 16:14:22 -0800547static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa,
548 bool is_loading);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800549
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800550#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
551 defined(IPA_CLIENT_IS_MHI_CONS))
552/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800553 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
554 * @priv_ctxt: hdd ipa local context
555 *
556 * Will be called by IPA context.
557 * It's atomic context, then should be scheduled to kworker thread
558 *
559 * Return: None
560 */
561static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
562{
563 struct hdd_ipa_priv *hdd_ipa;
564 struct op_msg_type *msg;
565 struct uc_op_work_struct *uc_op_work;
566
567 if (priv_ctxt == NULL) {
568 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
569 return;
570 }
571
572 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
Yun Park6edb2172018-01-14 00:18:05 -0800573 hdd_ipa->uc_loaded = true;
574
575 uc_op_work = &hdd_ipa->uc_op_work[HDD_IPA_UC_OPCODE_UC_READY];
576
577 if (!list_empty(&uc_op_work->work.entry))
578 /* uc_op_work is not initialized yet */
579 return;
580
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800581 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
582 if (!msg) {
583 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
584 return;
585 }
586
587 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
588
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800589 /* When the same uC OPCODE is already pended, just return */
590 if (uc_op_work->msg)
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530591 goto done;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800592
593 uc_op_work->msg = msg;
594 schedule_work(&uc_op_work->work);
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530595
jiadd91a6842017-08-01 14:46:02 +0800596 /* work handler will free the msg buffer */
597 return;
598
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530599done:
600 qdf_mem_free(msg);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800601}
602
603/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800604 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
605 * @ctrl: WDI control value
606 *
607 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
608 *
609 * Return: 0 on message send to ipa, -1 on failure
610 */
611static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
612{
Yun Park6c86a662017-10-05 16:09:15 -0700613 qdf_ipa_msg_meta_t meta;
614 qdf_ipa_wlan_msg_t *ipa_msg;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800615 int ret = 0;
616
617 /* WDI enable message to IPA */
Yun Park6c86a662017-10-05 16:09:15 -0700618 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg);
619 ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800620 if (ipa_msg == NULL) {
621 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
622 "msg allocation failed");
623 return -ENOMEM;
624 }
625
626 if (ctrl == true)
Yun Park6c86a662017-10-05 16:09:15 -0700627 QDF_IPA_MSG_META_MSG_TYPE(&meta) = WLAN_WDI_ENABLE;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800628 else
Yun Park6c86a662017-10-05 16:09:15 -0700629 QDF_IPA_MSG_META_MSG_TYPE(&meta) = WLAN_WDI_DISABLE;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800630
Srinivas Girigowda97852372017-03-06 16:52:59 -0800631 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park6c86a662017-10-05 16:09:15 -0700632 "ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
633 ret = qdf_ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800634 if (ret) {
635 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
636 "ipa_send_msg(Evt:%d)-fail=%d",
Yun Park6c86a662017-10-05 16:09:15 -0700637 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800638 qdf_mem_free(ipa_msg);
639 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800640 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800641}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800642
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800643/**
644 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
645 * @hdd_ipa: HDD IPA local context
646 *
647 * Register IPA UC ready callback function to IPA kernel driver
648 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
649 * open WDI pipe after WLAN driver loading finished
650 *
651 * Return: 0 Success
652 * -EPERM Registration fail
653 */
654static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
655{
Yun Park6c86a662017-10-05 16:09:15 -0700656 qdf_ipa_wdi_uc_ready_params_t uc_ready_param;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800657 int ret = 0;
658
659 hdd_ipa->uc_loaded = false;
Yun Park6c86a662017-10-05 16:09:15 -0700660 QDF_IPA_UC_READY_PARAMS_PRIV(&uc_ready_param) = (void *)hdd_ipa;
661 QDF_IPA_UC_READY_PARAMS_NOTIFY(&uc_ready_param) =
662 hdd_ipa_uc_loaded_uc_cb;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800663 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
664 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
665 "UC Ready CB register fail");
666 return -EPERM;
667 }
Yun Park6c86a662017-10-05 16:09:15 -0700668 if (false != QDF_IPA_UC_READY_PARAMS_IS_UC_READY(&uc_ready_param)) {
Srinivas Girigowda2b5d47c2017-03-29 00:28:46 -0700669 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800670 hdd_ipa->uc_loaded = true;
671 } else {
672 ret = hdd_ipa_uc_send_wdi_control_msg(false);
673 }
674
675 return ret;
676}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800677#else
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800678static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
679{
680 hdd_ipa->uc_loaded = true;
681 return 0;
682}
683
684static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
685{
686 return 0;
687}
688#endif
689
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800690/**
691 * hdd_ipa_is_enabled() - Is IPA enabled?
692 * @hdd_ctx: Global HDD context
693 *
694 * Return: true if IPA is enabled, false otherwise
695 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700696bool hdd_ipa_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800697{
698 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
699}
700
701/**
702 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
703 * @hdd_ctx: Global HDD context
704 *
705 * Return: true if IPA uC offload is enabled, false otherwise
706 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700707bool hdd_ipa_uc_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708{
709 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
710}
711
712/**
713 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
714 * @hdd_ctx: Global HDD context
715 *
716 * Return: true if STA mode IPA uC offload is enabled, false otherwise
717 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700718static inline bool hdd_ipa_uc_sta_is_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_UC_STA_ENABLE_MASK);
721}
722
723/**
Guolei Bianca144d82016-11-10 11:07:42 +0800724 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
725 * @hdd_ipa: Global HDD IPA context
726 *
727 * Return: None
728 */
Guolei Bianca144d82016-11-10 11:07:42 +0800729static inline void hdd_ipa_uc_sta_reset_sta_connected(
730 struct hdd_ipa_priv *hdd_ipa)
731{
Yun Park637d6482016-10-05 10:51:33 -0700732 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800733 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700734 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800735}
Guolei Bianca144d82016-11-10 11:07:42 +0800736
737/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800738 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
739 * @hdd_ipa: Global HDD IPA context
740 *
741 * Return: true if pre-filter is enabled, otherwise false
742 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700743static inline bool hdd_ipa_is_pre_filter_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800744{
745 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
746 HDD_IPA_PRE_FILTER_ENABLE_MASK);
747}
748
749/**
750 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
751 * @hdd_ipa: Global HDD IPA context
752 *
753 * Return: true if IPv6 is enabled, otherwise false
754 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700755static inline bool hdd_ipa_is_ipv6_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800756{
757 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
758}
759
760/**
761 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
762 * @hdd_ipa: Global HDD IPA context
763 *
764 * Return: true if resource manager is enabled, otherwise false
765 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700766static inline bool hdd_ipa_is_rm_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800767{
768 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
769}
770
771/**
772 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
773 * @hdd_ipa: Global HDD IPA context
774 *
775 * Return: true if resource manager is enabled, otherwise false
776 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700777static inline bool hdd_ipa_is_rt_debugging_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800778{
779 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
780}
781
782/**
783 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
784 * @hdd_ipa: Global HDD IPA context
785 *
786 * Return: true if clock scaling is enabled, otherwise false
787 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700788static inline bool hdd_ipa_is_clk_scaling_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800789{
790 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
791 HDD_IPA_CLK_SCALING_ENABLE_MASK |
792 HDD_IPA_RM_ENABLE_MASK);
793}
794
795/**
796 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
797 * @ctext: pointer to hdd context.
798 *
799 * If rt debug enabled, periodically called, and fill debug buffer
800 *
801 * Return: none
802 */
803static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
804{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700805 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800806 struct hdd_ipa_priv *hdd_ipa;
807 struct uc_rt_debug_info *dump_info = NULL;
808
809 if (wlan_hdd_validate_context(hdd_ctx))
810 return;
811
812 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700813 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800814 return;
815 }
816
817 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
818
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530819 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820 dump_info = &hdd_ipa->rt_bug_buffer[
821 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
822
Deepthi Gowri6acee342016-10-28 15:00:38 +0530823 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800824 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
Yun Park46255682017-10-09 15:56:34 -0700825 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internal_drop_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800826 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800827 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800828 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
829 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800830 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
831 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530832 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833
Anurag Chouhan210db072016-02-22 18:42:15 +0530834 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800835 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
836}
837
838/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700839 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840 * @hdd_ctx: pointer to hdd context.
841 *
842 * If rt debug enabled, dump debug buffer contents based on requirement
843 *
844 * Return: none
845 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700846static void __hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847{
848 struct hdd_ipa_priv *hdd_ipa;
849 unsigned int dump_count;
850 unsigned int dump_index;
851 struct uc_rt_debug_info *dump_info = NULL;
852
853 if (wlan_hdd_validate_context(hdd_ctx))
854 return;
855
856 hdd_ipa = hdd_ctx->hdd_ipa;
857 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700858 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859 return;
860 }
861
Chris Guo1751acf2017-07-03 14:09:01 +0800862 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
863 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -0700864 "IPA RT debug is not enabled");
Chris Guo1751acf2017-07-03 14:09:01 +0800865 return;
866 }
867
Yun Park46255682017-10-09 15:56:34 -0700868 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800869 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Yun Park46255682017-10-09 15:56:34 -0700870 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Parkb187d542016-11-14 18:10:04 -0800871 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800872
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530873 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800874 for (dump_count = 0;
875 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
876 dump_count++) {
877 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
878 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
879 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Yun Park46255682017-10-09 15:56:34 -0700880 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530881 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882 dump_info->time, dump_info->ipa_excep_count,
883 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800884 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800885 dump_info->rx_destructor_call,
886 dump_info->rx_discard_count);
887 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530888 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Yun Park46255682017-10-09 15:56:34 -0700889 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800890 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
891}
892
893/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700894 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
895 * __hdd_ipa_uc_rt_debug_host_dump
896 * @hdd_ctx: pointer to hdd context.
897 *
898 * If rt debug enabled, dump debug buffer contents based on requirement
899 *
900 * Return: none
901 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700902void hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700903{
904 cds_ssr_protect(__func__);
905 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
906 cds_ssr_unprotect(__func__);
907}
908
909/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800910 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
911 * @ctext: pointer to hdd context.
912 *
913 * periodically called by timer expire
914 * will try to alloc dummy memory and detect out of memory condition
915 * if out of memory detected, dump wlan-ipa stats
916 *
917 * Return: none
918 */
919static void hdd_ipa_uc_rt_debug_handler(void *ctext)
920{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700921 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700922 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800923 void *dummy_ptr = NULL;
924
925 if (wlan_hdd_validate_context(hdd_ctx))
926 return;
927
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700928 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
929
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800930 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700931 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
932 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933 return;
934 }
935
936 /* Allocate dummy buffer periodically and free immediately. this will
937 * proactively detect OOM and if allocation fails dump ipa stats
938 */
939 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
940 GFP_KERNEL | GFP_ATOMIC);
941 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800942 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
943 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -0700944 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
945 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800946 } else {
947 kfree(dummy_ptr);
948 }
949
Anurag Chouhan210db072016-02-22 18:42:15 +0530950 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951 HDD_IPA_UC_RT_DEBUG_PERIOD);
952}
953
954/**
Yun Parkb187d542016-11-14 18:10:04 -0800955 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800956 * @skb: packet pinter
957 *
958 * when free data packet, will be invoked by wlan client and will increase
959 * free counter
960 *
961 * Return: none
962 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700963static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964{
965 if (!ghdd_ipa) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700966 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "invalid hdd context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800967 return;
968 }
969
970 ghdd_ipa->ipa_rx_destructor_count++;
971}
972
973/**
Yun Parkb187d542016-11-14 18:10:04 -0800974 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800975 * @hdd_ctx: hdd main context
976 *
977 * free all rt debugging resources
978 *
979 * Return: none
980 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700981static void hdd_ipa_uc_rt_debug_deinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800982{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700983 struct hdd_ipa_priv *hdd_ipa;
984
985 if (wlan_hdd_validate_context(hdd_ctx))
986 return;
987
988 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530990 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800991
992 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700993 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
994 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800995 return;
996 }
997
Anurag Chouhan210db072016-02-22 18:42:15 +0530998 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -0800999 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1000 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1001 }
1002 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1003
1004 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301005 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1006 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001007 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301008 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001009}
1010
1011/**
Yun Parkb187d542016-11-14 18:10:04 -08001012 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001013 * @hdd_ctx: hdd main context
1014 *
1015 * alloc and initialize all rt debugging resources
1016 *
1017 * Return: none
1018 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001019static void hdd_ipa_uc_rt_debug_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001020{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001021 struct hdd_ipa_priv *hdd_ipa;
1022
Chris Guo1751acf2017-07-03 14:09:01 +08001023 if (wlan_hdd_validate_context_in_loading(hdd_ctx))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001024 return;
1025
1026 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301028 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001029 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301030 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001031 sizeof(struct uc_rt_debug_info) *
1032 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1033 hdd_ipa->ipa_tx_forward = 0;
1034 hdd_ipa->ipa_rx_discard = 0;
1035 hdd_ipa->ipa_rx_net_send_count = 0;
Yun Park46255682017-10-09 15:56:34 -07001036 hdd_ipa->ipa_rx_internal_drop_count = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001037 hdd_ipa->ipa_rx_destructor_count = 0;
1038
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 /* Reatime debug enable on feature enable */
1040 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001041 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1042 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043 return;
1044 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001045
1046 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1047 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1048 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1049 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1050
Anurag Chouhan210db072016-02-22 18:42:15 +05301051 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301053 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054 HDD_IPA_UC_RT_DEBUG_PERIOD);
1055
1056}
1057
1058/**
Yun Parkb187d542016-11-14 18:10:04 -08001059 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1060 * @hdd_ipa: HDD IPA struct
1061 *
1062 * Dump entries in struct hdd_ipa
1063 *
1064 * Return: none
1065 */
1066static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1067{
1068 int i;
1069
1070 /* HDD IPA */
Yun Park46255682017-10-09 15:56:34 -07001071 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1072 "\n==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001073 "num_iface: %d\n"
1074 "rm_state: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001075 "rm_lock: %pK\n"
1076 "uc_rm_work: %pK\n"
1077 "uc_op_work: %pK\n"
1078 "wake_lock: %pK\n"
1079 "wake_lock_work: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001080 "wake_lock_released: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001081 "tx_ref_cnt: %d\n"
1082 "pm_queue_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001083 "\thead: %pK\n"
1084 "\ttail: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001085 "\tqlen: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001086 "pm_work: %pK\n"
1087 "pm_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001088 "suspended: %d\n",
1089 hdd_ipa->num_iface,
1090 hdd_ipa->rm_state,
1091 &hdd_ipa->rm_lock,
1092 &hdd_ipa->uc_rm_work,
1093 &hdd_ipa->uc_op_work,
1094 &hdd_ipa->wake_lock,
1095 &hdd_ipa->wake_lock_work,
1096 hdd_ipa->wake_lock_released,
Yun Parkb187d542016-11-14 18:10:04 -08001097 hdd_ipa->tx_ref_cnt.counter,
1098 hdd_ipa->pm_queue_head.head,
1099 hdd_ipa->pm_queue_head.tail,
1100 hdd_ipa->pm_queue_head.qlen,
1101 &hdd_ipa->pm_work,
1102 &hdd_ipa->pm_lock,
1103 hdd_ipa->suspended);
Yun Park46255682017-10-09 15:56:34 -07001104
1105 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1106 "\nq_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001107 "pend_desc_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001108 "\tnext: %pK\n"
1109 "\tprev: %pK\n"
1110 "hdd_ctx: %pK\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001111 "stats: %pK\n"
1112 "ipv4_notifier: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001113 "curr_prod_bw: %d\n"
1114 "curr_cons_bw: %d\n"
1115 "activated_fw_pipe: %d\n"
1116 "sap_num_connected_sta: %d\n"
1117 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001118 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001119 hdd_ipa->pend_desc_head.next,
1120 hdd_ipa->pend_desc_head.prev,
1121 hdd_ipa->hdd_ctx,
Yun Parkb187d542016-11-14 18:10:04 -08001122 &hdd_ipa->stats,
1123 &hdd_ipa->ipv4_notifier,
1124 hdd_ipa->curr_prod_bw,
1125 hdd_ipa->curr_cons_bw,
1126 hdd_ipa->activated_fw_pipe,
1127 hdd_ipa->sap_num_connected_sta,
Yun Park46255682017-10-09 15:56:34 -07001128 (unsigned int)hdd_ipa->sta_connected);
1129
1130 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1131 "\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001132 "rx_pipe_handle: 0x%x\n"
1133 "resource_loading: %d\n"
1134 "resource_unloading: %d\n"
1135 "pending_cons_req: %d\n"
1136 "pending_event----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001137 "\tanchor.next: %pK\n"
1138 "\tanchor.prev: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001139 "\tcount: %d\n"
1140 "\tmax_size: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001141 "event_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001142 "ipa_tx_packets_diff: %d\n"
1143 "ipa_rx_packets_diff: %d\n"
1144 "ipa_p_tx_packets: %d\n"
1145 "ipa_p_rx_packets: %d\n"
1146 "stat_req_reason: %d\n",
1147 hdd_ipa->tx_pipe_handle,
1148 hdd_ipa->rx_pipe_handle,
1149 hdd_ipa->resource_loading,
1150 hdd_ipa->resource_unloading,
1151 hdd_ipa->pending_cons_req,
1152 hdd_ipa->pending_event.anchor.next,
1153 hdd_ipa->pending_event.anchor.prev,
1154 hdd_ipa->pending_event.count,
1155 hdd_ipa->pending_event.max_size,
1156 &hdd_ipa->event_lock,
1157 hdd_ipa->ipa_tx_packets_diff,
1158 hdd_ipa->ipa_rx_packets_diff,
1159 hdd_ipa->ipa_p_tx_packets,
1160 hdd_ipa->ipa_p_rx_packets,
1161 hdd_ipa->stat_req_reason);
1162
Yun Park46255682017-10-09 15:56:34 -07001163 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1164 "\ncons_pipe_in----\n"
1165 "\tsys: %pK\n"
1166 "\tdl.comp_ring_base_pa: 0x%x\n"
1167 "\tdl.comp_ring_size: %d\n"
1168 "\tdl.ce_ring_base_pa: 0x%x\n"
1169 "\tdl.ce_door_bell_pa: 0x%x\n"
1170 "\tdl.ce_ring_size: %d\n"
1171 "\tdl.num_tx_buffers: %d\n"
1172 "prod_pipe_in----\n"
1173 "\tsys: %pK\n"
1174 "\tul.rdy_ring_base_pa: 0x%x\n"
1175 "\tul.rdy_ring_size: %d\n"
1176 "\tul.rdy_ring_rp_pa: 0x%x\n"
1177 "uc_loaded: %d\n"
1178 "wdi_enabled: %d\n"
1179 "rt_debug_fill_timer: %pK\n"
1180 "rt_debug_lock: %pK\n"
1181 "ipa_lock: %pK\n",
1182 &hdd_ipa->cons_pipe_in.sys,
1183 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.comp_ring_base_pa,
1184 hdd_ipa->cons_pipe_in.u.dl.comp_ring_size,
1185 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.ce_ring_base_pa,
1186 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.ce_door_bell_pa,
1187 hdd_ipa->cons_pipe_in.u.dl.ce_ring_size,
1188 hdd_ipa->cons_pipe_in.u.dl.num_tx_buffers,
1189 &hdd_ipa->prod_pipe_in.sys,
1190 (unsigned int)hdd_ipa->prod_pipe_in.u.ul.rdy_ring_base_pa,
1191 hdd_ipa->prod_pipe_in.u.ul.rdy_ring_size,
1192 (unsigned int)hdd_ipa->prod_pipe_in.u.ul.rdy_ring_rp_pa,
1193 hdd_ipa->uc_loaded,
1194 hdd_ipa->wdi_enabled,
1195 &hdd_ipa->rt_debug_fill_timer,
1196 &hdd_ipa->rt_debug_lock,
1197 &hdd_ipa->ipa_lock);
1198
1199 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1200 "\nvdev_to_iface----");
1201 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
1202 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1203 "\n\t[%d]=%d", i, hdd_ipa->vdev_to_iface[i]);
1204 }
1205 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1206 "\nvdev_offload_enabled----");
1207 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
1208 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1209 "\n\t[%d]=%d", i, hdd_ipa->vdev_offload_enabled[i]);
1210 }
1211 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1212 "\nassoc_stas_map ----");
Yun Parkb187d542016-11-14 18:10:04 -08001213 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Yun Park46255682017-10-09 15:56:34 -07001214 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1215 "\n\t[%d]: is_reserved=%d, sta_id=%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001216 hdd_ipa->assoc_stas_map[i].is_reserved,
1217 hdd_ipa->assoc_stas_map[i].sta_id);
1218 }
1219}
1220
1221/**
1222 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1223 * @hdd_ipa: HDD IPA struct
1224 *
1225 * Dump entire struct hdd_ipa_sys_pipe
1226 *
1227 * Return: none
1228 */
1229static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1230{
1231 int i;
1232
1233 /* IPA SYS Pipes */
Yun Park46255682017-10-09 15:56:34 -07001234 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1235 "\n==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001236
1237 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1238 struct hdd_ipa_sys_pipe *sys_pipe;
Yun Park6c86a662017-10-05 16:09:15 -07001239 qdf_ipa_sys_connect_params_t *ipa_sys_params;
Yun Parkb187d542016-11-14 18:10:04 -08001240
1241 sys_pipe = &hdd_ipa->sys_pipe[i];
1242 ipa_sys_params = &sys_pipe->ipa_sys_params;
1243
Yun Park46255682017-10-09 15:56:34 -07001244 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1245 "\nsys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001246 "\tconn_hdl: 0x%x\n"
1247 "\tconn_hdl_valid: %d\n"
1248 "\tnat_en: %d\n"
1249 "\thdr_len %d\n"
1250 "\thdr_additional_const_len: %d\n"
1251 "\thdr_ofst_pkt_size_valid: %d\n"
1252 "\thdr_ofst_pkt_size: %d\n"
1253 "\thdr_little_endian: %d\n"
1254 "\tmode: %d\n"
1255 "\tclient: %d\n"
1256 "\tdesc_fifo_sz: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001257 "\tpriv: %pK\n"
1258 "\tnotify: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001259 "\tskip_ep_cfg: %d\n"
1260 "\tkeep_ipa_awake: %d\n",
1261 i,
1262 sys_pipe->conn_hdl,
1263 sys_pipe->conn_hdl_valid,
Yun Park6c86a662017-10-05 16:09:15 -07001264 QDF_IPA_SYS_PARAMS_NAT_EN(ipa_sys_params),
1265 QDF_IPA_SYS_PARAMS_HDR_LEN(ipa_sys_params),
1266 QDF_IPA_SYS_PARAMS_HDR_ADDITIONAL_CONST_LEN(
1267 ipa_sys_params),
1268 QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE_VALID(
1269 ipa_sys_params),
1270 QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE(ipa_sys_params),
1271 QDF_IPA_SYS_PARAMS_HDR_LITTLE_ENDIAN(ipa_sys_params),
1272 QDF_IPA_SYS_PARAMS_MODE(ipa_sys_params),
1273 QDF_IPA_SYS_PARAMS_CLIENT(ipa_sys_params),
1274 QDF_IPA_SYS_PARAMS_DESC_FIFO_SZ(ipa_sys_params),
1275 QDF_IPA_SYS_PARAMS_PRIV(ipa_sys_params),
1276 QDF_IPA_SYS_PARAMS_NOTIFY(ipa_sys_params),
1277 QDF_IPA_SYS_PARAMS_SKIP_EP_CFG(ipa_sys_params),
1278 QDF_IPA_SYS_PARAMS_KEEP_IPA_AWAKE(ipa_sys_params));
Yun Parkb187d542016-11-14 18:10:04 -08001279 }
1280}
1281
1282/**
1283 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1284 * @hdd_ipa: HDD IPA struct
1285 *
1286 * Dump entire struct hdd_ipa_iface_context
1287 *
1288 * Return: none
1289 */
1290static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1291{
1292 int i;
1293
1294 /* IPA Interface Contexts */
Yun Park46255682017-10-09 15:56:34 -07001295 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1296 "\n==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001297
1298 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1299 struct hdd_ipa_iface_context *iface_context;
1300
1301 iface_context = &hdd_ipa->iface_context[i];
1302
Yun Park46255682017-10-09 15:56:34 -07001303 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1304 "\niface_context[%d]----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001305 "\thdd_ipa: %pK\n"
1306 "\tadapter: %pK\n"
1307 "\ttl_context: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001308 "\tcons_client: %d\n"
1309 "\tprod_client: %d\n"
1310 "\tiface_id: %d\n"
1311 "\tsta_id: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001312 "\tinterface_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001313 "\tifa_address: 0x%x\n",
1314 i,
1315 iface_context->hdd_ipa,
1316 iface_context->adapter,
1317 iface_context->tl_context,
1318 iface_context->cons_client,
1319 iface_context->prod_client,
1320 iface_context->iface_id,
1321 iface_context->sta_id,
1322 &iface_context->interface_lock,
1323 iface_context->ifa_address);
1324 }
1325}
1326
1327/**
1328 * hdd_ipa_dump_info() - dump HDD IPA struct
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001329 * @hdd_ctx: hdd main context
Yun Parkb187d542016-11-14 18:10:04 -08001330 *
1331 * Dump entire struct hdd_ipa
1332 *
1333 * Return: none
1334 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001335void hdd_ipa_dump_info(struct hdd_context *hdd_ctx)
Yun Parkb187d542016-11-14 18:10:04 -08001336{
1337 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1338
1339 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1340 hdd_ipa_dump_sys_pipe(hdd_ipa);
1341 hdd_ipa_dump_iface_context(hdd_ipa);
1342}
1343
1344/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001345 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1346 * enabled
1347 *
1348 * This routine is called to set TX flow info if IPA is enabled
1349 *
1350 * Return: None
1351 */
1352void hdd_ipa_set_tx_flow_info(void)
1353{
Jeff Johnson49d45e62017-08-29 14:30:42 -07001354 struct hdd_adapter *adapter;
Jeff Johnsond377dce2017-10-04 10:32:42 -07001355 struct hdd_station_ctx *sta_ctx;
Jeff Johnson87251032017-08-29 13:31:11 -07001356 struct hdd_ap_ctx *hdd_ap_ctx;
Jeff Johnsonca2530c2017-09-30 18:25:40 -07001357 struct hdd_hostapd_state *hostapd_state;
Dustin Brown4e565a42018-01-17 14:59:14 -08001358 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INIT;
1359 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INIT;
1360 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INIT;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001361 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1362 const char *p2pMode = "DEV";
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001363 struct hdd_context *hdd_ctx;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001364 cds_context_type *cds_ctx;
1365#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1366 uint8_t targetChannel = 0;
1367 uint8_t preAdapterChannel = 0;
1368 uint8_t channel24;
1369 uint8_t channel5;
Jeff Johnson49d45e62017-08-29 14:30:42 -07001370 struct hdd_adapter *preAdapterContext = NULL;
1371 struct hdd_adapter *adapter2_4 = NULL;
1372 struct hdd_adapter *adapter5 = NULL;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001373 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1374#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1375 struct wlan_objmgr_psoc *psoc;
1376
1377 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1378 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001379 hdd_err("HDD context is NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001380 return;
1381 }
1382
1383 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1384 if (!cds_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001385 hdd_err("Invalid CDS Context");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001386 return;
1387 }
1388
1389 psoc = hdd_ctx->hdd_psoc;
Dustin Brown920397d2017-12-13 16:27:50 -08001390
1391 hdd_for_each_adapter(hdd_ctx, adapter) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001392 switch (adapter->device_mode) {
1393 case QDF_STA_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001394 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001395 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001396 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001397 staChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001398 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001399 qdf_copy_macaddr(&staBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001400 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001401#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1402 targetChannel = staChannel;
1403#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1404 }
1405 break;
1406 case QDF_P2P_CLIENT_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001407 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001408 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001409 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001410 p2pChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001411 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001412 qdf_copy_macaddr(&p2pBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001413 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001414 p2pMode = "CLI";
1415#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1416 targetChannel = p2pChannel;
1417#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1418 }
1419 break;
1420 case QDF_P2P_GO_MODE:
1421 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1422 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001423 if (hostapd_state->bss_state == BSS_START
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001424 && hostapd_state->qdf_status ==
1425 QDF_STATUS_SUCCESS) {
Jeff Johnson01206862017-10-27 20:55:59 -07001426 p2pChannel = hdd_ap_ctx->operating_channel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001427 qdf_copy_macaddr(&p2pBssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001428 &adapter->mac_addr);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001429#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1430 targetChannel = p2pChannel;
1431#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1432 }
1433 p2pMode = "GO";
1434 break;
1435 case QDF_SAP_MODE:
1436 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1437 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001438 if (hostapd_state->bss_state == BSS_START
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001439 && hostapd_state->qdf_status ==
1440 QDF_STATUS_SUCCESS) {
Jeff Johnson01206862017-10-27 20:55:59 -07001441 apChannel = hdd_ap_ctx->operating_channel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001442 qdf_copy_macaddr(&apBssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001443 &adapter->mac_addr);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001444#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1445 targetChannel = apChannel;
1446#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1447 }
1448 break;
1449 case QDF_IBSS_MODE:
1450 default:
1451 break;
1452 }
1453#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1454 if (targetChannel) {
1455 /*
1456 * This is first adapter detected as active
1457 * set as default for none concurrency case
1458 */
1459 if (!preAdapterChannel) {
1460 /* If IPA UC data path is enabled,
1461 * target should reserve extra tx descriptors
1462 * for IPA data path.
1463 * Then host data path should allow less TX
1464 * packet pumping in case IPA
1465 * data path enabled
1466 */
1467 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1468 (QDF_SAP_MODE == adapter->device_mode)) {
1469 adapter->tx_flow_low_watermark =
1470 hdd_ctx->config->TxFlowLowWaterMark +
1471 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1472 } else {
1473 adapter->tx_flow_low_watermark =
1474 hdd_ctx->config->
1475 TxFlowLowWaterMark;
1476 }
1477 adapter->tx_flow_high_watermark_offset =
1478 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1479 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001480 adapter->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001481 hdd_ctx->config->TxFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001482 hdd_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001483 adapter->device_mode,
1484 targetChannel,
1485 adapter->tx_flow_low_watermark,
1486 adapter->tx_flow_low_watermark +
1487 adapter->tx_flow_high_watermark_offset,
1488 hdd_ctx->config->TxFlowMaxQueueDepth);
1489 preAdapterChannel = targetChannel;
1490 preAdapterContext = adapter;
1491 } else {
1492 /*
1493 * SCC, disable TX flow control for both
1494 * SCC each adapter cannot reserve dedicated
1495 * channel resource, as a result, if any adapter
1496 * blocked OS Q by flow control,
1497 * blocked adapter will lost chance to recover
1498 */
1499 if (preAdapterChannel == targetChannel) {
1500 /* Current adapter */
1501 adapter->tx_flow_low_watermark = 0;
1502 adapter->
1503 tx_flow_high_watermark_offset = 0;
1504 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001505 adapter->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001506 hdd_ctx->config->
1507 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001508 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001509 hdd_device_mode_to_string(
1510 adapter->device_mode),
1511 adapter->device_mode,
1512 targetChannel,
1513 adapter->tx_flow_low_watermark,
1514 adapter->tx_flow_low_watermark +
1515 adapter->
1516 tx_flow_high_watermark_offset,
1517 hdd_ctx->config->
1518 TxHbwFlowMaxQueueDepth);
1519
1520 if (!preAdapterContext) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001521 hdd_err("SCC: Previous adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001522 continue;
1523 }
1524
1525 /* Previous adapter */
1526 preAdapterContext->
1527 tx_flow_low_watermark = 0;
1528 preAdapterContext->
1529 tx_flow_high_watermark_offset = 0;
1530 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001531 preAdapterContext->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001532 hdd_ctx->config->
1533 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001534 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001535 hdd_device_mode_to_string(
1536 preAdapterContext->device_mode
1537 ),
1538 preAdapterContext->device_mode,
1539 targetChannel,
1540 preAdapterContext->
1541 tx_flow_low_watermark,
1542 preAdapterContext->
1543 tx_flow_low_watermark +
1544 preAdapterContext->
1545 tx_flow_high_watermark_offset,
1546 hdd_ctx->config->
1547 TxHbwFlowMaxQueueDepth);
1548 }
1549 /*
1550 * MCC, each adapter will have dedicated
1551 * resource
1552 */
1553 else {
1554 /* current channel is 2.4 */
1555 if (targetChannel <=
1556 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1557 channel24 = targetChannel;
1558 channel5 = preAdapterChannel;
1559 adapter2_4 = adapter;
1560 adapter5 = preAdapterContext;
1561 } else {
1562 /* Current channel is 5 */
1563 channel24 = preAdapterChannel;
1564 channel5 = targetChannel;
1565 adapter2_4 = preAdapterContext;
1566 adapter5 = adapter;
1567 }
1568
1569 if (!adapter5) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001570 hdd_err("MCC: 5GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001571 continue;
1572 }
1573 adapter5->tx_flow_low_watermark =
1574 hdd_ctx->config->
1575 TxHbwFlowLowWaterMark;
1576 adapter5->
1577 tx_flow_high_watermark_offset =
1578 hdd_ctx->config->
1579 TxHbwFlowHighWaterMarkOffset;
1580 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001581 adapter5->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001582 hdd_ctx->config->
1583 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001584 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001585 hdd_device_mode_to_string(
1586 adapter5->device_mode),
1587 adapter5->device_mode,
1588 channel5,
1589 adapter5->tx_flow_low_watermark,
1590 adapter5->
1591 tx_flow_low_watermark +
1592 adapter5->
1593 tx_flow_high_watermark_offset,
1594 hdd_ctx->config->
1595 TxHbwFlowMaxQueueDepth);
1596
1597 if (!adapter2_4) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001598 hdd_err("MCC: 2.4GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001599 continue;
1600 }
1601 adapter2_4->tx_flow_low_watermark =
1602 hdd_ctx->config->
1603 TxLbwFlowLowWaterMark;
1604 adapter2_4->
1605 tx_flow_high_watermark_offset =
1606 hdd_ctx->config->
1607 TxLbwFlowHighWaterMarkOffset;
1608 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001609 adapter2_4->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001610 hdd_ctx->config->
1611 TxLbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001612 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001613 hdd_device_mode_to_string(
1614 adapter2_4->device_mode),
1615 adapter2_4->device_mode,
1616 channel24,
1617 adapter2_4->
1618 tx_flow_low_watermark,
1619 adapter2_4->
1620 tx_flow_low_watermark +
1621 adapter2_4->
1622 tx_flow_high_watermark_offset,
1623 hdd_ctx->config->
1624 TxLbwFlowMaxQueueDepth);
1625
1626 }
1627 }
1628 }
1629 targetChannel = 0;
1630#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001631 }
Dustin Brown920397d2017-12-13 16:27:50 -08001632
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001633 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1634}
1635
1636/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001637 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001639 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1640 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641 *
1642 * Return: true if IPA is enabled, false otherwise
1643 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001644static void __hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1646{
1647 struct hdd_ipa_priv *hdd_ipa;
1648
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001649 *ipa_tx_diff = 0;
1650 *ipa_rx_diff = 0;
1651
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001652 if (wlan_hdd_validate_context(hdd_ctx))
1653 return;
1654
1655 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1656
1657 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1658 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001659 return;
1660 }
1661
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301662 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001663 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1664 (false == hdd_ipa->resource_loading)) {
1665 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1666 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001667 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301668 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001669}
1670
1671/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001672 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1673 * @hdd_ctx: Global HDD context
1674 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1675 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1676 *
1677 * Return: true if IPA is enabled, false otherwise
1678 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001679void hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001680 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1681{
1682 cds_ssr_protect(__func__);
1683 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1684 cds_ssr_unprotect(__func__);
1685}
1686
1687/**
1688 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 * @adapter: network adapter
1690 * @reason: STAT REQ Reason
1691 *
1692 * Return: None
1693 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07001694static void __hdd_ipa_uc_stat_request(struct hdd_adapter *adapter,
1695 uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001696{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001697 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698 struct hdd_ipa_priv *hdd_ipa;
1699
Yun Park637d6482016-10-05 10:51:33 -07001700 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
Jeff Johnson399c6272017-08-30 10:51:00 -07001703 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001704
1705 if (wlan_hdd_validate_context(hdd_ctx))
1706 return;
1707
1708 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1709 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1710 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711 return;
1712 }
1713
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301714 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001715 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1716 (false == hdd_ipa->resource_loading)) {
1717 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07001718 qdf_mutex_release(&hdd_ipa->ipa_lock);
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001719 sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07001720 adapter->session_id,
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001721 WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001723 } else {
1724 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001726}
1727
1728/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001729 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1730 * @adapter: network adapter
1731 * @reason: STAT REQ Reason
1732 *
1733 * Return: None
1734 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001735void hdd_ipa_uc_stat_request(struct hdd_adapter *adapter, uint8_t reason)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001736{
1737 cds_ssr_protect(__func__);
1738 __hdd_ipa_uc_stat_request(adapter, reason);
1739 cds_ssr_unprotect(__func__);
1740}
1741
Yun Park637d6482016-10-05 10:51:33 -07001742#ifdef FEATURE_METERING
1743/**
1744 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
1745 * @adapter: network adapter
1746 * @reset_stats: reset stat countis after response
1747 *
1748 * Return: None
1749 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001750void hdd_ipa_uc_sharing_stats_request(struct hdd_adapter *adapter,
Yun Park637d6482016-10-05 10:51:33 -07001751 uint8_t reset_stats)
1752{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001753 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001754 struct hdd_ipa_priv *hdd_ipa;
1755
1756 if (!adapter)
1757 return;
1758
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001759 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1760 hdd_ipa = hdd_ctx->hdd_ipa;
1761 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1762 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001763 return;
1764 }
1765
Yun Park637d6482016-10-05 10:51:33 -07001766 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001767 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001768 qdf_mutex_release(&hdd_ipa->ipa_lock);
1769 wma_cli_set_command(
Jeff Johnson1b780e42017-10-31 14:11:45 -07001770 (int)adapter->session_id,
Yun Park637d6482016-10-05 10:51:33 -07001771 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
1772 reset_stats, VDEV_CMD);
1773 } else {
1774 qdf_mutex_release(&hdd_ipa->ipa_lock);
1775 }
1776}
1777
1778/**
1779 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
1780 * @adapter: network adapter
1781 * @set_quota: when 1, FW starts quota monitoring
1782 * @quota_bytes: quota limit in bytes
1783 *
1784 * Return: None
1785 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001786void hdd_ipa_uc_set_quota(struct hdd_adapter *adapter, uint8_t set_quota,
Yun Park637d6482016-10-05 10:51:33 -07001787 uint64_t quota_bytes)
1788{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001789 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001790 struct hdd_ipa_priv *hdd_ipa;
1791
1792 if (!adapter)
1793 return;
1794
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001795 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1796 hdd_ipa = hdd_ctx->hdd_ipa;
1797 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1798 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001799 return;
1800 }
1801
1802 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
1803 set_quota, quota_bytes);
1804
1805 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001806 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001807 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park327e7812017-02-14 15:18:10 -08001808 wma_cli_set2_command(
Jeff Johnson1b780e42017-10-31 14:11:45 -07001809 (int)adapter->session_id,
Yun Park637d6482016-10-05 10:51:33 -07001810 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
Yun Park327e7812017-02-14 15:18:10 -08001811 (set_quota ? quota_bytes&0xffffffff : 0),
1812 (set_quota ? quota_bytes>>32 : 0),
1813 VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001814 } else {
1815 qdf_mutex_release(&hdd_ipa->ipa_lock);
1816 }
1817}
1818#endif
1819
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001820/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1822 * @hdd_ipa: Global HDD IPA context
1823 * @sta_add: Should station be added
1824 * @sta_id: ID of the station being queried
1825 *
1826 * Return: true if the station was found
1827 */
1828static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1829 bool sta_add, uint8_t sta_id)
1830{
1831 bool sta_found = false;
1832 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001833
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001834 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1835 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1836 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1837 sta_found = true;
1838 break;
1839 }
1840 }
1841 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301842 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001843 "STA ID %d already exist, cannot add", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844 return sta_found;
1845 }
1846 if (sta_add) {
1847 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1848 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1849 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1850 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1851 return sta_found;
1852 }
1853 }
1854 }
1855 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301856 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001857 "STA ID %d does not exist, cannot delete", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858 return sta_found;
1859 }
1860 if (!sta_add) {
1861 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1862 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1863 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1864 hdd_ipa->assoc_stas_map[idx].is_reserved =
1865 false;
1866 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1867 return sta_found;
1868 }
1869 }
1870 }
1871 return sta_found;
1872}
1873
1874/**
1875 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1876 * @hdd_ipa: Global HDD IPA context
1877 *
1878 * Return: 0 on success, negative errno if error
1879 */
1880static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1881{
Yun Parkfec73dc2017-09-06 10:40:07 -07001882 int result = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07001883 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07001884 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885
Yun Parke4239802018-01-09 11:01:40 -08001886 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Park199c2ed2017-10-02 11:24:22 -07001887
1888 if (!hdd_ipa->ipa_pipes_down) {
1889 /*
1890 * This shouldn't happen :
1891 * IPA WDI Pipes are already activated
1892 */
1893 WARN_ON(1);
1894 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
1895 "IPA WDI Pipes are already activated");
1896 goto end;
1897 }
Yun Parkfec73dc2017-09-06 10:40:07 -07001898
Yun Parkb4f591d2017-03-29 15:51:01 -07001899 result = cdp_ipa_enable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301901 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001902 "Enable PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001903 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001904 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001905
Yun Park777d7242017-03-30 15:38:33 -07001906 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Leo Change3e49442015-10-26 20:07:13 -07001907 hdd_ipa->ipa_pipes_down = false;
Yun Parkb4f591d2017-03-29 15:51:01 -07001908
1909 cdp_ipa_enable_autonomy(soc, (struct cdp_pdev *)pdev);
1910
Yun Parkfec73dc2017-09-06 10:40:07 -07001911end:
Yun Parke4239802018-01-09 11:01:40 -08001912 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07001913 hdd_ipa->ipa_pipes_down);
Yun Park199c2ed2017-10-02 11:24:22 -07001914
Yun Parkfec73dc2017-09-06 10:40:07 -07001915 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001916}
1917
1918/**
1919 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1920 * @hdd_ipa: Global HDD IPA context
1921 *
1922 * Return: 0 on success, negative errno if error
1923 */
1924static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1925{
Yun Parkb4f591d2017-03-29 15:51:01 -07001926 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1927 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkfec73dc2017-09-06 10:40:07 -07001928 int result = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001929
Yun Parke4239802018-01-09 11:01:40 -08001930 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Park199c2ed2017-10-02 11:24:22 -07001931
1932 if (hdd_ipa->ipa_pipes_down) {
1933 /*
1934 * This shouldn't happen :
1935 * IPA WDI Pipes are already deactivated
1936 */
1937 WARN_ON(1);
1938 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
1939 "IPA WDI Pipes are already deactivated");
1940 goto end;
1941 }
Leo Change3e49442015-10-26 20:07:13 -07001942
Yun Parkb4f591d2017-03-29 15:51:01 -07001943 cdp_ipa_disable_autonomy(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001944
Yun Parkb4f591d2017-03-29 15:51:01 -07001945 result = cdp_ipa_disable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301947 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001948 "Disable WDI PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001949 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950 }
1951
Yun Parkfec73dc2017-09-06 10:40:07 -07001952 hdd_ipa->ipa_pipes_down = true;
1953
1954end:
Yun Parke4239802018-01-09 11:01:40 -08001955 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07001956 hdd_ipa->ipa_pipes_down);
1957 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958}
1959
1960/**
1961 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1962 * @hdd_ipa: Global HDD IPA context
1963 *
1964 * Return: 0 on success, negative errno if error
1965 */
1966static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1967{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001968 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07001969
Yun Parke4239802018-01-09 11:01:40 -08001970 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07001971
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972 hdd_ipa->activated_fw_pipe = 0;
1973 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001974
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001975 /* If RM feature enabled
1976 * Request PROD Resource first
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07001977 * PROD resource may return sync or async manners
1978 */
Yun Parkb4f591d2017-03-29 15:51:01 -07001979 if (hdd_ipa_is_rm_enabled(hdd_ctx)) {
Yun Park4cab6ee2015-10-27 11:43:40 -07001980 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1981 /* RM PROD request sync return
1982 * enable pipe immediately
1983 */
1984 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301985 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001986 "IPA WDI Pipe activation failed");
Yun Park4cab6ee2015-10-27 11:43:40 -07001987 hdd_ipa->resource_loading = false;
1988 return -EBUSY;
1989 }
Sravan Kumar Kairamc76f28a2017-07-25 19:03:40 +05301990 } else {
1991 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park199c2ed2017-10-02 11:24:22 -07001992 "IPA WDI Pipe activation deferred");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 }
1994 } else {
1995 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001996 * Just enabled all the PIPEs
1997 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301999 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002000 "IPA WDI Pipe activation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002001 hdd_ipa->resource_loading = false;
2002 return -EBUSY;
2003 }
2004 hdd_ipa->resource_loading = false;
2005 }
Yun Park4cab6ee2015-10-27 11:43:40 -07002006
Yun Parke4239802018-01-09 11:01:40 -08002007 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002008 return 0;
2009}
2010
2011/**
2012 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
2013 * @hdd_ipa: Global HDD IPA context
2014 *
2015 * Return: None
2016 */
2017static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
2018{
Leo Changfdb45c32016-10-28 11:09:23 -07002019 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07002020 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021
Yun Parke4239802018-01-09 11:01:40 -08002022 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07002023
Yun Parkb4f591d2017-03-29 15:51:01 -07002024 if (!pdev) {
Yun Park7c4f31b2016-11-30 10:09:21 -08002025 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2026 QDF_ASSERT(0);
2027 return;
2028 }
2029
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002030 hdd_ipa->resource_unloading = true;
Yun Park777d7242017-03-30 15:38:33 -07002031 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Yun Parkb4f591d2017-03-29 15:51:01 -07002032 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW RX PIPE");
2033 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, false);
Yun Parkfec73dc2017-09-06 10:40:07 -07002034
Yun Parke4239802018-01-09 11:01:40 -08002035 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: IPA WDI Pipes deactivated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002036}
2037
2038/**
2039 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2040 * @context: User context registered with TL (the IPA Global context is
2041 * registered
2042 * @rxpkt: Packet containing the notification
2043 * @staid: ID of the station associated with the packet
2044 *
2045 * Return: None
2046 */
2047static void
Yun Park6c86a662017-10-05 16:09:15 -07002048hdd_ipa_uc_rm_notify_handler(void *context, qdf_ipa_rm_event_t event)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002049{
2050 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302051 QDF_STATUS status = QDF_STATUS_SUCCESS;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002052 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002053
2054 /*
2055 * When SSR is going on or driver is unloading, just return.
2056 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002057 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302058 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002059 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002060
Yun Parkb4f591d2017-03-29 15:51:01 -07002061 if (!hdd_ipa_is_rm_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062 return;
2063
Yun Park46255682017-10-09 15:56:34 -07002064 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event code %d",
2065 event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002066
2067 switch (event) {
2068 case IPA_RM_RESOURCE_GRANTED:
2069 /* Differed RM Granted */
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302070 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002071 if ((false == hdd_ipa->resource_unloading) &&
2072 (!hdd_ipa->activated_fw_pipe)) {
2073 hdd_ipa_uc_enable_pipes(hdd_ipa);
2074 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302075 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 break;
2077
2078 case IPA_RM_RESOURCE_RELEASED:
2079 /* Differed RM Released */
2080 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081 break;
2082
2083 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302084 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07002085 "invalid event code %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002086 break;
2087 }
2088}
2089
2090/**
2091 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2092 * @hdd_ipa: Global HDD IPA context
2093 * @event: IPA resource manager event to be deferred
2094 *
2095 * This function is called when a resource manager event is received
2096 * from firmware in interrupt context. This function will defer the
2097 * handling to the OL RX thread
2098 *
2099 * Return: None
2100 */
2101static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2102{
Yun Park6c86a662017-10-05 16:09:15 -07002103 qdf_ipa_rm_event_t event;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002104 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2105 struct uc_rm_work_struct, work);
2106 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2107 struct hdd_ipa_priv, uc_rm_work);
2108
2109 cds_ssr_protect(__func__);
2110 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002111 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07002112 "posted event %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002113
2114 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2115 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002116}
2117
2118/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002119 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
Yun Parkb4f591d2017-03-29 15:51:01 -07002120 * @hdd_ipa: hdd ipa local context
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002121 *
2122 * Will handle IPA UC image loaded indication comes from IPA kernel
2123 *
2124 * Return: None
2125 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002126static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *hdd_ipa)
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002127{
Yun Parkb4f591d2017-03-29 15:51:01 -07002128 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2129 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002130 struct hdd_context *hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07002131 QDF_STATUS status;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002132
Yun Park46255682017-10-09 15:56:34 -07002133 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC READY");
Yun Parkb4f591d2017-03-29 15:51:01 -07002134 if (true == hdd_ipa->uc_loaded) {
Yun Park46255682017-10-09 15:56:34 -07002135 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "UC already loaded");
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002136 return;
2137 }
2138
Yun Parkb4f591d2017-03-29 15:51:01 -07002139 hdd_ctx = hdd_ipa->hdd_ctx;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002140
Yun Parkb4f591d2017-03-29 15:51:01 -07002141 /* Connect pipe */
2142 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
2143 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
2144 hdd_ipa_wdi_meter_notifier_cb,
2145 hdd_ctx->config->IpaDescSize,
2146 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
2147 &hdd_ipa->tx_pipe_handle,
2148 &hdd_ipa->rx_pipe_handle);
2149 if (status) {
2150 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2151 "Failure to setup IPA pipes (status=%d)",
2152 status);
2153 return;
2154 }
2155
2156 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002157
2158 /* If already any STA connected, enable IPA/FW PIPEs */
Yun Parkb4f591d2017-03-29 15:51:01 -07002159 if (hdd_ipa->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002160 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002161 "Client already connected, enable IPA/FW PIPEs");
Yun Parkb4f591d2017-03-29 15:51:01 -07002162 hdd_ipa_uc_handle_first_con(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002163 }
2164}
2165
2166/**
Yun Park637d6482016-10-05 10:51:33 -07002167 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2168 * @hdd_ctx: Global HDD context
2169 * @op_msg: operation message received from firmware
2170 *
2171 * Return: QDF_STATUS enumeration
2172 */
2173#ifdef FEATURE_METERING
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002174static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002175 struct op_msg_type *op_msg)
2176{
2177 struct op_msg_type *msg = op_msg;
2178 struct ipa_uc_sharing_stats *uc_sharing_stats;
2179 struct ipa_uc_quota_rsp *uc_quota_rsp;
2180 struct ipa_uc_quota_ind *uc_quota_ind;
2181 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002182 struct hdd_adapter *adapter;
Yun Park637d6482016-10-05 10:51:33 -07002183
2184 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2185
2186 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2187 /* fill-up ipa_uc_sharing_stats structure from FW */
2188 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2189 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2190
2191 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2192 sizeof(struct ipa_uc_sharing_stats));
2193
2194 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2195
2196 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2197 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2198 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2199 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2200 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2201 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2202 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2203 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2204 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2205 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2206 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2207 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2208 /* received set quota response */
2209 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2210 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2211
2212 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2213 sizeof(struct ipa_uc_quota_rsp));
2214
2215 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2216 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2217 "%s: success=%d, quota_bytes=%llu",
2218 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2219 hdd_ipa->ipa_quota_rsp.success,
2220 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2221 hdd_ipa->ipa_quota_rsp.quota_lo);
2222 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2223 /* hit quota limit */
2224 uc_quota_ind = (struct ipa_uc_quota_ind *)
2225 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2226
2227 hdd_ipa->ipa_quota_ind.quota_bytes =
2228 uc_quota_ind->quota_bytes;
2229
2230 /* send quota exceeded indication to IPA */
2231 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2232 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2233 hdd_ipa->ipa_quota_ind.quota_bytes);
2234
2235 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2236 if (adapter)
2237 ipa_broadcast_wdi_quota_reach_ind(
2238 adapter->dev->ifindex,
2239 uc_quota_ind->quota_bytes);
2240 else
2241 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2242 "Failed quota_reach_ind: NULL adapter");
2243 } else {
2244 return QDF_STATUS_E_INVAL;
2245 }
2246
2247 return QDF_STATUS_SUCCESS;
2248}
2249#else
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002250static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002251 struct op_msg_type *op_msg)
2252{
2253 return QDF_STATUS_E_INVAL;
2254}
2255#endif
2256
Yun Park657c7d72017-06-07 15:44:59 -07002257#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0))
2258/* older versions had a typo */
2259#define num_bam_int_in_non_running_state num_bam_int_in_non_runnning_state
2260#endif
2261
Yun Park637d6482016-10-05 10:51:33 -07002262/**
Yun Park46255682017-10-09 15:56:34 -07002263 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
2264 * @event: IPA WLAN event to be converted to a string
2265 *
2266 * Return: ASCII string representing the IPA WLAN event
2267 */
Yun Park6c86a662017-10-05 16:09:15 -07002268static inline char *hdd_ipa_wlan_event_to_str(qdf_ipa_wlan_event_t event)
Yun Park46255682017-10-09 15:56:34 -07002269{
2270 switch (event) {
2271 CASE_RETURN_STRING(WLAN_CLIENT_CONNECT);
2272 CASE_RETURN_STRING(WLAN_CLIENT_DISCONNECT);
2273 CASE_RETURN_STRING(WLAN_CLIENT_POWER_SAVE_MODE);
2274 CASE_RETURN_STRING(WLAN_CLIENT_NORMAL_MODE);
2275 CASE_RETURN_STRING(SW_ROUTING_ENABLE);
2276 CASE_RETURN_STRING(SW_ROUTING_DISABLE);
2277 CASE_RETURN_STRING(WLAN_AP_CONNECT);
2278 CASE_RETURN_STRING(WLAN_AP_DISCONNECT);
2279 CASE_RETURN_STRING(WLAN_STA_CONNECT);
2280 CASE_RETURN_STRING(WLAN_STA_DISCONNECT);
2281 CASE_RETURN_STRING(WLAN_CLIENT_CONNECT_EX);
2282 default:
2283 return "UNKNOWN";
2284 }
2285}
2286
2287/**
2288 * hdd_ipa_print_session_info - Print IPA session info
2289 * @hdd_ipa: HDD IPA local context
2290 *
2291 * Return: None
2292 */
2293static void hdd_ipa_print_session_info(struct hdd_ipa_priv *hdd_ipa)
2294{
2295 uint8_t session_id;
2296 int device_mode;
2297 struct ipa_uc_pending_event *event = NULL, *next = NULL;
2298 struct hdd_ipa_iface_context *iface_context = NULL;
2299 int i;
2300
2301 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2302 "\n==== IPA SESSION INFO ====\n"
2303 "NUM IFACE: %d\n"
2304 "RM STATE: %d\n"
2305 "ACTIVATED FW PIPE: %d\n"
2306 "SAP NUM STAs: %d\n"
2307 "STA CONNECTED: %d\n"
2308 "CONCURRENT MODE: %s\n"
2309 "RSC LOADING: %d\n"
2310 "RSC UNLOADING: %d\n"
2311 "PENDING CONS REQ: %d\n"
2312 "IPA PIPES DOWN: %d\n"
2313 "IPA UC LOADED: %d\n"
2314 "IPA WDI ENABLED: %d\n"
2315 "NUM SEND MSG: %d\n"
2316 "NUM FREE MSG: %d\n",
2317 hdd_ipa->num_iface,
2318 hdd_ipa->rm_state,
2319 hdd_ipa->activated_fw_pipe,
2320 hdd_ipa->sap_num_connected_sta,
2321 hdd_ipa->sta_connected,
2322 (hdd_ipa->hdd_ctx->mcc_mode ? "MCC" : "SCC"),
2323 hdd_ipa->resource_loading,
2324 hdd_ipa->resource_unloading,
2325 hdd_ipa->pending_cons_req,
2326 hdd_ipa->ipa_pipes_down,
2327 hdd_ipa->uc_loaded,
2328 hdd_ipa->wdi_enabled,
2329 (unsigned int)hdd_ipa->stats.num_send_msg,
2330 (unsigned int)hdd_ipa->stats.num_free_msg);
2331
2332 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2333 iface_context = &hdd_ipa->iface_context[i];
2334 if (!iface_context || !iface_context->adapter)
2335 continue;
2336
Jeff Johnson1b780e42017-10-31 14:11:45 -07002337 session_id = iface_context->adapter->session_id;
Yun Park46255682017-10-09 15:56:34 -07002338 if (session_id >= CSR_ROAM_SESSION_MAX)
2339 continue;
2340
2341 device_mode = iface_context->adapter->device_mode;
2342 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2343 "\nIFACE[%d]: session:%d, sta_id:%d, mode:%s, offload:%d",
2344 i, session_id,
2345 iface_context->sta_id,
2346 hdd_device_mode_to_string(device_mode),
2347 hdd_ipa->vdev_offload_enabled[session_id]);
2348 }
2349
2350 for (i = 0; i < IPA_WLAN_EVENT_MAX; i++)
2351 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2352 "\nEVENT[%d]=%d",
2353 i, hdd_ipa->stats.event[i]);
2354
2355 i = 0;
2356 qdf_list_peek_front(&hdd_ipa->pending_event,
2357 (qdf_list_node_t **)&event);
2358 while (event != NULL) {
2359 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2360 "\nPENDING EVENT[%d]: DEV:%s, EVT:%s, sta_id:%d, MAC:%pM",
2361 i, event->adapter->dev->name,
2362 hdd_ipa_wlan_event_to_str(event->type),
2363 event->sta_id, event->mac_addr);
2364
2365 qdf_list_peek_next(&hdd_ipa->pending_event,
2366 (qdf_list_node_t *)event, (qdf_list_node_t **)&next);
2367 event = next;
2368 next = NULL;
2369 i++;
2370 }
2371}
2372
2373/**
2374 * hdd_ipa_print_txrx_stats - Print HDD IPA TX/RX stats
2375 * @hdd_ipa: HDD IPA local context
2376 *
2377 * Return: None
2378 */
2379static void hdd_ipa_print_txrx_stats(struct hdd_ipa_priv *hdd_ipa)
2380{
2381 int i;
2382 struct hdd_ipa_iface_context *iface_context = NULL;
2383
2384 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2385 "\n==== HDD IPA TX/RX STATS ====\n"
2386 "NUM RM GRANT: %llu\n"
2387 "NUM RM RELEASE: %llu\n"
2388 "NUM RM GRANT IMM: %llu\n"
2389 "NUM CONS PERF REQ: %llu\n"
2390 "NUM PROD PERF REQ: %llu\n"
2391 "NUM RX DROP: %llu\n"
2392 "NUM EXCP PKT: %llu\n"
2393 "NUM TX FWD OK: %llu\n"
2394 "NUM TX FWD ERR: %llu\n"
2395 "NUM TX DESC Q CNT: %llu\n"
2396 "NUM TX DESC ERROR: %llu\n"
2397 "NUM TX COMP CNT: %llu\n"
2398 "NUM TX QUEUED: %llu\n"
2399 "NUM TX DEQUEUED: %llu\n"
2400 "NUM MAX PM QUEUE: %llu\n"
2401 "TX REF CNT: %d\n"
2402 "SUSPENDED: %d\n"
2403 "PEND DESC HEAD: %pK\n"
2404 "TX DESC LIST: %pK\n"
2405 "FREE TX DESC HEAD: %pK\n",
2406 hdd_ipa->stats.num_rm_grant,
2407 hdd_ipa->stats.num_rm_release,
2408 hdd_ipa->stats.num_rm_grant_imm,
2409 hdd_ipa->stats.num_cons_perf_req,
2410 hdd_ipa->stats.num_prod_perf_req,
2411 hdd_ipa->stats.num_rx_drop,
2412 hdd_ipa->stats.num_rx_excep,
2413 hdd_ipa->stats.num_tx_fwd_ok,
2414 hdd_ipa->stats.num_tx_fwd_err,
2415 hdd_ipa->stats.num_tx_desc_q_cnt,
2416 hdd_ipa->stats.num_tx_desc_error,
2417 hdd_ipa->stats.num_tx_comp_cnt,
2418 hdd_ipa->stats.num_tx_queued,
2419 hdd_ipa->stats.num_tx_dequeued,
2420 hdd_ipa->stats.num_max_pm_queue,
2421 hdd_ipa->tx_ref_cnt.counter,
2422 hdd_ipa->suspended,
2423 &hdd_ipa->pend_desc_head,
2424 hdd_ipa->tx_desc_list,
2425 &hdd_ipa->free_tx_desc_head);
2426
2427 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2428 iface_context = &hdd_ipa->iface_context[i];
2429 if (!iface_context || !iface_context->adapter)
2430 continue;
2431
2432 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2433 "IFACE[%d]: TX:%llu, TX DROP:%llu, TX ERR:%llu, TX CAC DROP:%llu, RX IPA EXCEP:%llu",
2434 i,
2435 iface_context->stats.num_tx,
2436 iface_context->stats.num_tx_drop,
2437 iface_context->stats.num_tx_err,
2438 iface_context->stats.num_tx_cac_drop,
2439 iface_context->stats.num_rx_ipa_excep);
2440 }
2441}
2442
2443/**
2444 * hdd_ipa_print_fw_wdi_stats - Print WLAN FW WDI stats
2445 * @hdd_ipa: HDD IPA local context
2446 *
2447 * Return: None
2448 */
2449static void hdd_ipa_print_fw_wdi_stats(struct hdd_ipa_priv *hdd_ipa,
2450 struct ipa_uc_fw_stats *uc_fw_stat)
2451{
2452 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2453 "\n==== WLAN FW WDI TX STATS ====\n"
2454 "COMP RING BASE: 0x%x\n"
2455 "COMP RING SIZE: %d\n"
2456 "COMP RING DBELL : 0x%x\n"
2457 "COMP RING DBELL IND VAL : %d\n"
2458 "COMP RING DBELL CACHED VAL : %d\n"
2459 "PKTS ENQ : %d\n"
2460 "PKTS COMP : %d\n"
2461 "IS SUSPEND : %d\n",
2462 uc_fw_stat->tx_comp_ring_base,
2463 uc_fw_stat->tx_comp_ring_size,
2464 uc_fw_stat->tx_comp_ring_dbell_addr,
2465 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2466 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2467 uc_fw_stat->tx_pkts_enqueued,
2468 uc_fw_stat->tx_pkts_completed,
2469 uc_fw_stat->tx_is_suspend);
2470
2471 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2472 "\n==== WLAN FW WDI RX STATS ====\n"
2473 "IND RING BASE: 0x%x\n"
2474 "IND RING SIZE: %d\n"
2475 "IND RING DBELL : 0x%x\n"
2476 "IND RING DBELL IND VAL : %d\n"
2477 "IND RING DBELL CACHED VAL : %d\n"
2478 "RDY IND ADDR : 0x%x\n"
2479 "RDY IND CACHE VAL : %d\n"
2480 "RFIL IND : %d\n"
2481 "NUM PKT INDICAT : %d\n"
2482 "BUF REFIL : %d\n"
2483 "NUM DROP NO SPC : %d\n"
2484 "NUM DROP NO BUF : %d\n"
2485 "IS SUSPND : %d\n",
2486 uc_fw_stat->rx_ind_ring_base,
2487 uc_fw_stat->rx_ind_ring_size,
2488 uc_fw_stat->rx_ind_ring_dbell_addr,
2489 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2490 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2491 uc_fw_stat->rx_ind_ring_rdidx_addr,
2492 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2493 uc_fw_stat->rx_refill_idx,
2494 uc_fw_stat->rx_num_pkts_indicated,
2495 uc_fw_stat->rx_buf_refilled,
2496 uc_fw_stat->rx_num_ind_drop_no_space,
2497 uc_fw_stat->rx_num_ind_drop_no_buf,
2498 uc_fw_stat->rx_is_suspend);
2499}
2500
2501/**
2502 * hdd_ipa_print_ipa_wdi_stats - Print IPA WDI stats
2503 * @hdd_ipa: HDD IPA local context
2504 *
2505 * Return: None
2506 */
2507static void hdd_ipa_print_ipa_wdi_stats(struct hdd_ipa_priv *hdd_ipa)
2508{
2509 struct IpaHwStatsWDIInfoData_t ipa_stat;
2510
2511 ipa_get_wdi_stats(&ipa_stat);
2512
2513 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2514 "\n==== IPA WDI TX STATS ====\n"
2515 "NUM PROCD : %d\n"
2516 "CE DBELL : 0x%x\n"
2517 "NUM DBELL FIRED : %d\n"
2518 "COMP RNG FULL : %d\n"
2519 "COMP RNG EMPT : %d\n"
2520 "COMP RNG USE HGH : %d\n"
2521 "COMP RNG USE LOW : %d\n"
2522 "BAM FIFO FULL : %d\n"
2523 "BAM FIFO EMPT : %d\n"
2524 "BAM FIFO USE HGH : %d\n"
2525 "BAM FIFO USE LOW : %d\n"
2526 "NUM DBELL : %d\n"
2527 "NUM UNEXP DBELL : %d\n"
2528 "NUM BAM INT HDL : 0x%x\n"
2529 "NUM BAM INT NON-RUN : 0x%x\n"
2530 "NUM QMB INT HDL : 0x%x\n",
2531 ipa_stat.tx_ch_stats.num_pkts_processed,
2532 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2533 ipa_stat.tx_ch_stats.num_db_fired,
2534 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2535 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2536 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2537 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2538 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2539 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2540 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2541 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2542 ipa_stat.tx_ch_stats.num_db,
2543 ipa_stat.tx_ch_stats.num_unexpected_db,
2544 ipa_stat.tx_ch_stats.num_bam_int_handled,
2545 ipa_stat.tx_ch_stats.
2546#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
2547 num_bam_int_in_non_running_state,
2548#else
2549 num_bam_int_in_non_runnning_state,
2550#endif
2551 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2552
2553 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2554 "\n==== IPA WDI RX STATS ====\n"
2555 "MAX OST PKT : %d\n"
2556 "NUM PKT PRCSD : %d\n"
2557 "RNG RP : 0x%x\n"
2558 "IND RNG FULL : %d\n"
2559 "IND RNG EMPT : %d\n"
2560 "IND RNG USE HGH : %d\n"
2561 "IND RNG USE LOW : %d\n"
2562 "BAM FIFO FULL : %d\n"
2563 "BAM FIFO EMPT : %d\n"
2564 "BAM FIFO USE HGH : %d\n"
2565 "BAM FIFO USE LOW : %d\n"
2566 "NUM DB : %d\n"
2567 "NUM UNEXP DB : %d\n"
2568 "NUM BAM INT HNDL : 0x%x\n",
2569 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2570 ipa_stat.rx_ch_stats.num_pkts_processed,
2571 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2572 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2573 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2574 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2575 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2576 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2577 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2578 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2579 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2580 ipa_stat.rx_ch_stats.num_db,
2581 ipa_stat.rx_ch_stats.num_unexpected_db,
2582 ipa_stat.rx_ch_stats.num_bam_int_handled);
2583}
2584
2585/**
2586 * hdd_ipa_uc_info() - Print IPA uC resource and session information
2587 * @adapter: network adapter
2588 *
2589 * Return: None
2590 */
2591void hdd_ipa_uc_info(struct hdd_context *hdd_ctx)
2592{
2593 struct hdd_ipa_priv *hdd_ipa;
2594
2595 hdd_ipa = hdd_ctx->hdd_ipa;
2596
2597 if (!hdd_ipa) {
2598 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2599 "HDD IPA context is NULL");
2600 return;
2601 }
2602
2603 /* IPA session info */
2604 hdd_ipa_print_session_info(hdd_ipa);
2605}
2606
2607/**
2608 * hdd_ipa_uc_stat() - Print IPA uC stats
2609 * @adapter: network adapter
2610 *
2611 * Return: None
2612 */
2613void hdd_ipa_uc_stat(struct hdd_adapter *adapter)
2614{
2615 struct hdd_context *hdd_ctx;
2616 struct hdd_ipa_priv *hdd_ipa;
2617
2618 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2619 hdd_ipa = hdd_ctx->hdd_ipa;
2620
2621 if (!hdd_ipa) {
2622 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2623 "HDD IPA context is NULL");
2624 return;
2625 }
2626
2627 /* HDD IPA TX/RX stats */
2628 hdd_ipa_print_txrx_stats(hdd_ipa);
2629 /* IPA WDI stats */
2630 hdd_ipa_print_ipa_wdi_stats(hdd_ipa);
2631 /* WLAN FW WDI stats */
2632 hdd_ipa_uc_stat_request(adapter, HDD_IPA_UC_STAT_REASON_DEBUG);
2633}
2634
2635/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002636 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2637 * @op_msg: operation message received from firmware
2638 * @usr_ctxt: user context registered with TL (we register the HDD Global
2639 * context)
2640 *
2641 * Return: None
2642 */
2643static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2644{
2645 struct op_msg_type *msg = op_msg;
2646 struct ipa_uc_fw_stats *uc_fw_stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002647 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002648 struct hdd_context *hdd_ctx;
Yun Parka658cf92018-01-24 17:19:29 -08002649 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2650 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302651 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002652
Alok Kumareff0d772018-02-09 16:01:06 +05302653 if (!pdev) {
2654 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
2655 return;
2656 }
2657
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002658 if (!op_msg || !usr_ctxt) {
Yun Park46255682017-10-09 15:56:34 -07002659 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "INVALID ARG");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002660 return;
2661 }
2662
2663 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302664 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07002665 "INVALID OPCODE %d", msg->op_code);
jiadd91a6842017-08-01 14:46:02 +08002666 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002667 return;
2668 }
2669
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002670 hdd_ctx = (struct hdd_context *) usr_ctxt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002671
2672 /*
2673 * When SSR is going on or driver is unloading, just return.
2674 */
2675 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302676 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302677 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002678 return;
2679 }
2680
2681 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2682
Govind Singhb6a89772016-08-12 11:23:35 +05302683 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002684 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002685
2686 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2687 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302688 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002689 hdd_ipa->activated_fw_pipe++;
2690 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2691 hdd_ipa->resource_loading = false;
Yun Park777d7242017-03-30 15:38:33 -07002692 complete(&hdd_ipa->ipa_resource_comp);
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002693 if (hdd_ipa->wdi_enabled == false) {
2694 hdd_ipa->wdi_enabled = true;
2695 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2696 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2697 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002698 }
Yun Parka4bb37c2017-12-08 16:14:22 -08002699 hdd_ipa_uc_proc_pending_event(hdd_ipa, true);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002700 if (hdd_ipa->pending_cons_req)
2701 ipa_rm_notify_completion(
2702 IPA_RM_RESOURCE_GRANTED,
2703 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002704 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002705 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302706 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002707 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Yun Parka658cf92018-01-24 17:19:29 -08002708 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302709 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parka658cf92018-01-24 17:19:29 -08002710
2711 if (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code) {
2712 hdd_ipa_uc_disable_pipes(hdd_ipa);
2713 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2714 "Disable FW TX PIPE");
2715 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev,
2716 false, true);
2717 }
2718
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002719 hdd_ipa->activated_fw_pipe--;
2720 if (!hdd_ipa->activated_fw_pipe) {
Yun Park777d7242017-03-30 15:38:33 -07002721 /*
2722 * Async return success from FW
2723 * Disable/suspend all the PIPEs
2724 */
Yun Parka4bb37c2017-12-08 16:14:22 -08002725 hdd_ipa->resource_unloading = false;
2726 complete(&hdd_ipa->ipa_resource_comp);
Yun Park5b635012015-12-02 15:05:01 -08002727 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2728 ipa_rm_release_resource(
2729 IPA_RM_RESOURCE_WLAN_PROD);
Yun Parka4bb37c2017-12-08 16:14:22 -08002730 hdd_ipa_uc_proc_pending_event(hdd_ipa, false);
Yun Park5b635012015-12-02 15:05:01 -08002731 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302733 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002734 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002735 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002736 uc_fw_stat = (struct ipa_uc_fw_stats *)
Yun Park46255682017-10-09 15:56:34 -07002737 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002738
Yun Park46255682017-10-09 15:56:34 -07002739 /* WLAN FW WDI stats */
2740 hdd_ipa_print_fw_wdi_stats(hdd_ipa, uc_fw_stat);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002741 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2742 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2743 /* STATs from FW */
2744 uc_fw_stat = (struct ipa_uc_fw_stats *)
2745 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302746 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002747 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2748 uc_fw_stat->tx_pkts_completed,
2749 hdd_ipa->ipa_p_tx_packets);
2750 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2751 (uc_fw_stat->rx_num_ind_drop_no_space +
2752 uc_fw_stat->rx_num_ind_drop_no_buf +
2753 uc_fw_stat->rx_num_pkts_indicated),
2754 hdd_ipa->ipa_p_rx_packets);
2755
2756 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2757 hdd_ipa->ipa_p_rx_packets =
2758 (uc_fw_stat->rx_num_ind_drop_no_space +
2759 uc_fw_stat->rx_num_ind_drop_no_buf +
2760 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302761 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002762 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2763 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2764 hdd_ipa_uc_loaded_handler(hdd_ipa);
2765 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002766 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2767 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2768 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002769 }
Yun Park8957d802017-01-25 12:27:29 -08002770
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302771 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002772}
2773
2774
2775/**
2776 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2777 * @adapter: device adapter instance
2778 * @offload_type: MCC or SCC
2779 * @enable: TX offload enable or disable
2780 *
2781 * Return: none
2782 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07002783static void hdd_ipa_uc_offload_enable_disable(struct hdd_adapter *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002784 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002785{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002786 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002787 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002788 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002789 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002790
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002791 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002792 return;
2793
Yun Park8292dcb2016-10-07 16:46:06 -07002794 iface_context = adapter->ipa_context;
Jeff Johnson1b780e42017-10-31 14:11:45 -07002795 session_id = adapter->session_id;
Yun Park8292dcb2016-10-07 16:46:06 -07002796
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002797 if (!iface_context) {
2798 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2799 "Interface context is NULL");
2800 return;
2801 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08002802 if (session_id >= CSR_ROAM_SESSION_MAX) {
2803 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2804 "invalid session id: %d", session_id);
2805 return;
2806 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002807 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park199c2ed2017-10-02 11:24:22 -07002808 /*
2809 * This shouldn't happen :
2810 * IPA offload status is already set as desired
2811 */
2812 WARN_ON(1);
2813 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
Yun Parkb4f591d2017-03-29 15:51:01 -07002814 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002815 "IPA offload status is already set",
2816 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002817 return;
2818 }
2819
Jeff Johnson1b780e42017-10-31 14:11:45 -07002820 if (wlan_hdd_validate_session_id(adapter->session_id)) {
Yun Park4540e862016-11-10 16:30:06 -08002821 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2822 "invalid session id: %d, offload_type=%d, enable=%d",
Jeff Johnson1b780e42017-10-31 14:11:45 -07002823 adapter->session_id, offload_type, enable);
Yun Park4540e862016-11-10 16:30:06 -08002824 return;
2825 }
2826
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302827 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002828 sizeof(ipa_offload_enable_disable));
2829 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002830 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002831 ipa_offload_enable_disable.enable = enable;
2832
Yun Park199c2ed2017-10-02 11:24:22 -07002833 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07002834 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002835 ipa_offload_enable_disable.offload_type,
2836 ipa_offload_enable_disable.vdev_id,
2837 ipa_offload_enable_disable.enable);
2838
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302839 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002840 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07002841 adapter->session_id, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302842 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07002843 "Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2844 ipa_offload_enable_disable.offload_type,
2845 ipa_offload_enable_disable.vdev_id,
2846 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002847 } else {
2848 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002849 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002850 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002851 }
2852}
2853
2854/**
2855 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2856 * @work: uC OP work
2857 *
2858 * Return: None
2859 */
2860static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2861{
2862 struct op_msg_type *msg;
2863 struct uc_op_work_struct *uc_op_work = container_of(work,
2864 struct uc_op_work_struct, work);
2865 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2866
2867 cds_ssr_protect(__func__);
2868
2869 msg = uc_op_work->msg;
2870 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002871 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07002872 "posted msg %d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002873
2874 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2875
2876 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002877}
2878
2879/**
2880 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2881 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2882 * @op_msg: operation message received from firmware
2883 * @hdd_ctx: Global HDD context
2884 *
2885 * Return: None
2886 */
2887static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2888{
2889 struct hdd_ipa_priv *hdd_ipa;
2890 struct op_msg_type *msg;
2891 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302892 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002893
2894 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302895 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002896 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002897
2898 msg = (struct op_msg_type *)op_msg;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002899 hdd_ipa = ((struct hdd_context *)hdd_ctx)->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002900
2901 if (unlikely(!hdd_ipa))
2902 goto end;
2903
2904 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Yun Parkb4f591d2017-03-29 15:51:01 -07002905 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid OP Code (%d)",
2906 msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002907 goto end;
2908 }
2909
2910 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2911 if (uc_op_work->msg)
2912 /* When the same uC OPCODE is already pended, just return */
2913 goto end;
2914
2915 uc_op_work->msg = msg;
2916 schedule_work(&uc_op_work->work);
2917 return;
2918
2919end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302920 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002921}
2922
2923/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002924 * hdd_ipa_init_uc_op_work - init ipa uc op work
2925 * @work: struct work_struct
2926 * @work_handler: work_handler
2927 *
2928 * Return: none
2929 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002930static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002931 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002932{
2933 INIT_WORK(work, work_handler);
2934}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002935
Yun Park637d6482016-10-05 10:51:33 -07002936#ifdef FEATURE_METERING
2937/**
2938 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2939 * IPA calls to get WLAN stats or set quota limit.
2940 * @priv: pointer to private data registered with IPA (we register a
2941 *» pointer to the global IPA context)
2942 * @evt: the IPA event which triggered the callback
2943 * @data: data associated with the event
2944 *
2945 * Return: None
2946 */
Yun Park6c86a662017-10-05 16:09:15 -07002947static void __hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Park637d6482016-10-05 10:51:33 -07002948 void *data)
2949{
2950 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002951 struct hdd_adapter *adapter = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07002952 qdf_ipa_get_wdi_sap_stats_t *wdi_sap_stats;
2953 qdf_ipa_set_wifi_quota_t *ipa_set_quota;
Yun Park637d6482016-10-05 10:51:33 -07002954 int ret = 0;
2955
2956 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2957 return;
2958
2959 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2960
2961 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2962
2963 switch (evt) {
2964 case IPA_GET_WDI_SAP_STATS:
2965 /* fill-up ipa_get_wdi_sap_stats structure after getting
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07002966 * ipa_uc_fw_stats from FW
2967 */
Yun Park637d6482016-10-05 10:51:33 -07002968 wdi_sap_stats = data;
2969
2970 if (!adapter) {
2971 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2972 "IPA uC share stats failed - no adapter");
Yun Park6c86a662017-10-05 16:09:15 -07002973 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) =
2974 0;
Yun Park637d6482016-10-05 10:51:33 -07002975 return;
2976 }
2977
2978 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
Yun Park637d6482016-10-05 10:51:33 -07002979 hdd_ipa_uc_sharing_stats_request(adapter,
Yun Park6c86a662017-10-05 16:09:15 -07002980 QDF_IPA_GET_WDI_SAP_STATS_RESET_STATS(wdi_sap_stats));
Yun Park637d6482016-10-05 10:51:33 -07002981 ret = wait_for_completion_timeout(
2982 &hdd_ipa->ipa_uc_sharing_stats_comp,
2983 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2984 if (!ret) {
2985 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2986 "IPA uC share stats request timed out");
Yun Park6c86a662017-10-05 16:09:15 -07002987 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
2988 = 0;
Yun Park637d6482016-10-05 10:51:33 -07002989 } else {
Yun Park6c86a662017-10-05 16:09:15 -07002990 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
2991 = 1;
Yun Park637d6482016-10-05 10:51:33 -07002992
Yun Park6c86a662017-10-05 16:09:15 -07002993 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(wdi_sap_stats)
2994 = hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2995 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(wdi_sap_stats)
2996 = hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2997 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(wdi_sap_stats)
2998 = hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2999 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(wdi_sap_stats)
3000 = hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
3001 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(wdi_sap_stats)
3002 = hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
3003 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(wdi_sap_stats)
3004 = hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
3005 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(wdi_sap_stats)
3006 = hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
3007 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(wdi_sap_stats)
3008 = hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
Yun Park637d6482016-10-05 10:51:33 -07003009 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
3010 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
3011 "IPA_GET_WDI_SAP_STATS",
Yun Park6c86a662017-10-05 16:09:15 -07003012 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(
3013 wdi_sap_stats),
3014 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(
3015 wdi_sap_stats),
3016 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(
3017 wdi_sap_stats),
3018 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(
3019 wdi_sap_stats),
3020 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(
3021 wdi_sap_stats),
3022 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(
3023 wdi_sap_stats),
3024 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(
3025 wdi_sap_stats),
3026 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(
3027 wdi_sap_stats),
3028 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(
3029 wdi_sap_stats));
Yun Park637d6482016-10-05 10:51:33 -07003030 }
3031 break;
3032 case IPA_SET_WIFI_QUOTA:
3033 /* get ipa_set_wifi_quota structure from IPA and pass to FW
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07003034 * through quota_exceeded field in ipa_uc_fw_stats
3035 */
Yun Park637d6482016-10-05 10:51:33 -07003036 ipa_set_quota = data;
3037
3038 if (!adapter) {
3039 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3040 "IPA uC set quota failed - no adapter");
3041 ipa_set_quota->set_valid = 0;
3042 return;
3043 }
3044
Yun Park777d7242017-03-30 15:38:33 -07003045 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
Yun Park637d6482016-10-05 10:51:33 -07003046 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
3047 ipa_set_quota->quota_bytes);
3048
3049 ret = wait_for_completion_timeout(
3050 &hdd_ipa->ipa_uc_set_quota_comp,
3051 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
3052 if (!ret) {
3053 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3054 "IPA uC set quota request timed out");
Yun Park6c86a662017-10-05 16:09:15 -07003055 QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = 0;
Yun Park637d6482016-10-05 10:51:33 -07003056 } else {
Yun Park6c86a662017-10-05 16:09:15 -07003057 QDF_IPA_SET_WIFI_QUOTA_BYTES(ipa_set_quota) =
Yun Park637d6482016-10-05 10:51:33 -07003058 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
3059 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
Yun Park6c86a662017-10-05 16:09:15 -07003060 QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) =
Yun Park637d6482016-10-05 10:51:33 -07003061 hdd_ipa->ipa_quota_rsp.success;
3062 }
3063
3064 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
3065 ipa_set_quota->quota_bytes,
3066 ipa_set_quota->set_valid);
3067 break;
3068 }
3069}
3070
3071/**
3072 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
3073 * IPA calls to get WLAN stats or set quota limit.
3074 * @priv: pointer to private data registered with IPA (we register a
Yun Parkb4f591d2017-03-29 15:51:01 -07003075 * pointer to the global IPA context)
Yun Park637d6482016-10-05 10:51:33 -07003076 * @evt: the IPA event which triggered the callback
3077 * @data: data associated with the event
3078 *
3079 * Return: None
3080 */
Yun Park6c86a662017-10-05 16:09:15 -07003081static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Park637d6482016-10-05 10:51:33 -07003082 void *data)
3083{
3084 cds_ssr_protect(__func__);
3085 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
3086 cds_ssr_unprotect(__func__);
3087}
3088
Yun Parkb4f591d2017-03-29 15:51:01 -07003089static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07003090{
Yun Park637d6482016-10-05 10:51:33 -07003091 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
3092 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
3093}
3094#else
Yun Parkb4f591d2017-03-29 15:51:01 -07003095static void hdd_ipa_wdi_meter_notifier_cb(void)
3096{
3097}
3098
3099static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07003100{
3101}
3102#endif
3103
Rajeev Kumar217f2172016-01-06 18:11:55 -08003104/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003105 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
3106 * @hdd_ctx: Global HDD context
3107 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003108 * This function is called to update IPA pipe configuration with resources
3109 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
3110 * (cds_enable)
3111 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303112 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003113 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003114QDF_STATUS hdd_ipa_uc_ol_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003115{
Yun Parkb4f591d2017-03-29 15:51:01 -07003116 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07003117 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08003118 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkb4f591d2017-03-29 15:51:01 -07003119 uint8_t i;
3120 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003121
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003122 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3123 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003124
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08003125 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003126
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003127 /* Do only IPA Pipe specific configuration here. All one time
3128 * initialization wrt IPA UC shall in hdd_ipa_init and those need
3129 * to be reinit at SSR shall in be SSR deinit / reinit functions.
3130 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003131 if (!pdev || !soc) {
3132 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkb4f591d2017-03-29 15:51:01 -07003133 status = QDF_STATUS_E_FAILURE;
Yun Parkbaa62862017-01-18 13:43:34 -08003134 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003135 }
Yun Parka4bb37c2017-12-08 16:14:22 -08003136
3137 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3138 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3139 hdd_ipa->vdev_offload_enabled[i] = false;
3140 }
3141
Yun Parkb4f591d2017-03-29 15:51:01 -07003142 if (cdp_ipa_get_resource(soc, (struct cdp_pdev *)pdev)) {
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003143 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
3144 "IPA UC resource alloc fail");
Yun Park199c2ed2017-10-02 11:24:22 -07003145 status = QDF_STATUS_E_FAILURE;
3146 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003147 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003148
Yun Parkb4f591d2017-03-29 15:51:01 -07003149 if (true == hdd_ipa->uc_loaded) {
3150 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
3151 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
3152 hdd_ipa_wdi_meter_notifier_cb,
3153 hdd_ctx->config->IpaDescSize,
3154 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
3155 &hdd_ipa->tx_pipe_handle,
3156 &hdd_ipa->rx_pipe_handle);
3157 if (status) {
Yun Parkbaa62862017-01-18 13:43:34 -08003158 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07003159 "Failure to setup IPA pipes (status=%d)",
3160 status);
Yun Park199c2ed2017-10-02 11:24:22 -07003161 status = QDF_STATUS_E_FAILURE;
3162 goto fail_return;
Yun Parkbaa62862017-01-18 13:43:34 -08003163 }
Yun Park637d6482016-10-05 10:51:33 -07003164
Yun Parkb4f591d2017-03-29 15:51:01 -07003165 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
3166 hdd_ipa_init_metering(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003167 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003168
Yun Parkb4f591d2017-03-29 15:51:01 -07003169 cdp_ipa_register_op_cb(soc, (struct cdp_pdev *)pdev,
Yun Parkbaa62862017-01-18 13:43:34 -08003170 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
3171
Yun Parkb4f591d2017-03-29 15:51:01 -07003172 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
3173 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
Yun Parka4bb37c2017-12-08 16:14:22 -08003174 hdd_ipa_uc_fw_op_event_handler);
Yun Parkb4f591d2017-03-29 15:51:01 -07003175 hdd_ipa->uc_op_work[i].msg = NULL;
3176 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003177
Yun Parkbaa62862017-01-18 13:43:34 -08003178fail_return:
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08003179 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: status=%d", status);
Yun Parkb4f591d2017-03-29 15:51:01 -07003180 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003181}
3182
Leo Change3e49442015-10-26 20:07:13 -07003183/**
Yun Parkd8fb1a82017-10-13 16:48:20 -07003184 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
3185 * @hdd_ipa: pointer to HDD IPA struct
3186 *
3187 * Return: none
3188 */
3189static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
3190{
3191 struct ipa_uc_pending_event *pending_event = NULL;
3192
3193 while (qdf_list_remove_front(&hdd_ipa->pending_event,
3194 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
3195 qdf_mem_free(pending_event);
3196}
3197
3198/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303199 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
3200 * @hdd_ctx: Global HDD context
3201 *
3202 * Return: 0 on success, negativer errno on error
3203 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003204int hdd_ipa_uc_ol_deinit(struct hdd_context *hdd_ctx)
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303205{
3206 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
Yun Park6edb2172018-01-14 00:18:05 -08003207 int i, ret = 0;
Yun Parkb4f591d2017-03-29 15:51:01 -07003208 QDF_STATUS status;
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303209
Yun Parke4239802018-01-09 11:01:40 -08003210 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003211
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303212 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3213 return ret;
3214
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05303215 if (!hdd_ipa->ipa_pipes_down)
3216 hdd_ipa_uc_disable_pipes(hdd_ipa);
3217
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303218 if (true == hdd_ipa->uc_loaded) {
Yun Parkb4f591d2017-03-29 15:51:01 -07003219 status = cdp_ipa_cleanup(cds_get_context(QDF_MODULE_ID_SOC),
3220 hdd_ipa->tx_pipe_handle,
3221 hdd_ipa->rx_pipe_handle);
3222 if (status) {
3223 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3224 "Failure to cleanup IPA pipes (status=%d)",
3225 status);
Yun Park6edb2172018-01-14 00:18:05 -08003226 ret = -EFAULT;
Yun Parkb4f591d2017-03-29 15:51:01 -07003227 }
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303228 }
3229
Yun Parka4bb37c2017-12-08 16:14:22 -08003230 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07003231 hdd_ipa_cleanup_pending_event(hdd_ipa);
Yun Parka4bb37c2017-12-08 16:14:22 -08003232 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07003233
Yun Park6edb2172018-01-14 00:18:05 -08003234 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
3235 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
3236 qdf_mem_free(hdd_ipa->uc_op_work[i].msg);
3237 hdd_ipa->uc_op_work[i].msg = NULL;
3238 }
3239
Yun Parke4239802018-01-09 11:01:40 -08003240 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: ret=%d", ret);
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303241 return ret;
3242}
3243
3244/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003245 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07003246 * @hdd_ctx: hdd main context
3247 *
3248 * Force shutdown IPA pipe
3249 * Independent of FW pipe status, IPA pipe shutdonw progress
3250 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3251 * independent from FW pipe status
3252 *
3253 * Return: NONE
3254 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003255static void __hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07003256{
3257 struct hdd_ipa_priv *hdd_ipa;
3258
Yun Parke4239802018-01-09 11:01:40 -08003259 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003260
Leo Change3e49442015-10-26 20:07:13 -07003261 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
3262 return;
3263
3264 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
3265 if (false == hdd_ipa->ipa_pipes_down) {
Yun Park46255682017-10-09 15:56:34 -07003266 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Parkb4f591d2017-03-29 15:51:01 -07003267 "IPA pipes are not down yet, force shutdown");
Leo Change3e49442015-10-26 20:07:13 -07003268 hdd_ipa_uc_disable_pipes(hdd_ipa);
3269 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003270 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb4f591d2017-03-29 15:51:01 -07003271 "IPA pipes are down, do nothing");
Leo Change3e49442015-10-26 20:07:13 -07003272 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003273
Yun Parke4239802018-01-09 11:01:40 -08003274 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Leo Change3e49442015-10-26 20:07:13 -07003275}
3276
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003277/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003278 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
3279 * __hdd_ipa_uc_force_pipe_shutdown
3280 * @hdd_ctx: hdd main context
3281 *
3282 * Force shutdown IPA pipe
3283 * Independent of FW pipe status, IPA pipe shutdonw progress
3284 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3285 * independent from FW pipe status
3286 *
3287 * Return: NONE
3288 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003289void hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003290{
3291 cds_ssr_protect(__func__);
3292 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
3293 cds_ssr_unprotect(__func__);
3294}
3295
3296/**
Govind Singh9c58eba2016-09-02 16:23:06 +05303297 * hdd_ipa_msg_free_fn() - Free an IPA message
3298 * @buff: pointer to the IPA message
3299 * @len: length of the IPA message
3300 * @type: type of IPA message
3301 *
3302 * Return: None
3303 */
3304static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
3305{
Srinivas Girigowda97852372017-03-06 16:52:59 -08003306 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05303307 ghdd_ipa->stats.num_free_msg++;
3308 qdf_mem_free(buff);
3309}
3310
Govind Singh9c58eba2016-09-02 16:23:06 +05303311/**
jge62037862016-12-09 10:44:33 +08003312 * hdd_ipa_uc_send_evt() - send event to ipa
3313 * @hdd_ctx: pointer to hdd context
3314 * @type: event type
3315 * @mac_addr: pointer to mac address
3316 *
3317 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303318 *
3319 * Return: 0 - Success
3320 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003321static int hdd_ipa_uc_send_evt(struct hdd_adapter *adapter,
Yun Park6c86a662017-10-05 16:09:15 -07003322 qdf_ipa_wlan_event_t type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303323{
jge62037862016-12-09 10:44:33 +08003324 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07003325 qdf_ipa_msg_meta_t meta;
3326 qdf_ipa_wlan_msg_t *msg;
Govind Singh9c58eba2016-09-02 16:23:06 +05303327 int ret = 0;
jge62037862016-12-09 10:44:33 +08003328
Yun Park6c86a662017-10-05 16:09:15 -07003329 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
3330 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
jge62037862016-12-09 10:44:33 +08003331 if (msg == NULL) {
3332 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3333 "msg allocation failed");
3334 return -ENOMEM;
3335 }
3336
Yun Park6c86a662017-10-05 16:09:15 -07003337 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
3338 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), adapter->dev->name,
jge62037862016-12-09 10:44:33 +08003339 IPA_RESOURCE_NAME_MAX);
Yun Park6c86a662017-10-05 16:09:15 -07003340 memcpy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, ETH_ALEN);
Yun Park199c2ed2017-10-02 11:24:22 -07003341 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Yun Park6c86a662017-10-05 16:09:15 -07003342 QDF_IPA_WLAN_MSG_NAME(msg), QDF_IPA_MSG_META_MSG_TYPE(&meta));
3343 ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
jge62037862016-12-09 10:44:33 +08003344 if (ret) {
3345 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3346 "%s: Evt: %d fail:%d",
Yun Park6c86a662017-10-05 16:09:15 -07003347 QDF_IPA_WLAN_MSG_NAME(msg),
3348 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
jge62037862016-12-09 10:44:33 +08003349 qdf_mem_free(msg);
3350 return ret;
3351 }
3352
3353 hdd_ipa->stats.num_send_msg++;
3354
3355 return ret;
3356}
3357
3358/**
3359 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3360 * @hdd_ctx: pointer to hdd adapter
3361 *
3362 * Send disconnect client event to IPA driver during SSR
3363 *
3364 * Return: 0 - Success
3365 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003366static int hdd_ipa_uc_disconnect_client(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003367{
3368 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3369 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303370 int i;
3371
Yun Parke4239802018-01-09 11:01:40 -08003372 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Govind Singh9c58eba2016-09-02 16:23:06 +05303373 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003374 if (qdf_is_macaddr_broadcast(&adapter->sta_info[i].sta_mac))
Govind Singh9c58eba2016-09-02 16:23:06 +05303375 continue;
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003376 if ((adapter->sta_info[i].in_use) &&
3377 (!adapter->sta_info[i].is_deauth_in_progress) &&
jge62037862016-12-09 10:44:33 +08003378 hdd_ipa->sap_num_connected_sta) {
3379 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003380 adapter->sta_info[i].sta_mac.bytes);
jge62037862016-12-09 10:44:33 +08003381 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303382 }
3383 }
Yun Parke4239802018-01-09 11:01:40 -08003384 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07003385 hdd_ipa->sap_num_connected_sta);
Govind Singh9c58eba2016-09-02 16:23:06 +05303386
3387 return ret;
3388}
3389
3390/**
jge62037862016-12-09 10:44:33 +08003391 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3392 * @hdd_ctx: pointer to hdd adapter
3393 *
3394 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303395 *
3396 * Return: 0 - Success
3397 */
jge62037862016-12-09 10:44:33 +08003398
Jeff Johnson49d45e62017-08-29 14:30:42 -07003399static int hdd_ipa_uc_disconnect_ap(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003400{
3401 int ret = 0;
3402
Yun Parke4239802018-01-09 11:01:40 -08003403 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003404 if (adapter->ipa_context) {
jge62037862016-12-09 10:44:33 +08003405 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3406 adapter->dev->dev_addr);
Yun Parkfec73dc2017-09-06 10:40:07 -07003407 }
Yun Parke4239802018-01-09 11:01:40 -08003408 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
jge62037862016-12-09 10:44:33 +08003409
3410 return ret;
3411}
3412
jge62037862016-12-09 10:44:33 +08003413/**
3414 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3415 * @hdd_ctx: pointer to hdd adapter
3416 *
3417 * Send disconnect sta event to IPA driver during SSR
3418 *
3419 * Return: 0 - Success
3420 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003421static int hdd_ipa_uc_disconnect_sta(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003422{
Jeff Johnsond377dce2017-10-04 10:32:42 -07003423 struct hdd_station_ctx *sta_ctx;
jge62037862016-12-09 10:44:33 +08003424 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3425 int ret = 0;
3426
Yun Parke4239802018-01-09 11:01:40 -08003427 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003428 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003429 hdd_ipa->sta_connected) {
Jeff Johnsond377dce2017-10-04 10:32:42 -07003430 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
jge62037862016-12-09 10:44:33 +08003431 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Jeff Johnsond377dce2017-10-04 10:32:42 -07003432 sta_ctx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003433 }
Yun Parke4239802018-01-09 11:01:40 -08003434 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
jge62037862016-12-09 10:44:33 +08003435
3436 return ret;
3437}
jge62037862016-12-09 10:44:33 +08003438
3439/**
3440 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3441 * @hdd_ctx: pointer to hdd context
3442 *
3443 * Send disconnect event to IPA driver during SSR
3444 *
3445 * Return: 0 - Success
3446 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003447static int hdd_ipa_uc_disconnect(struct hdd_context *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303448{
Jeff Johnson49d45e62017-08-29 14:30:42 -07003449 struct hdd_adapter *adapter;
Govind Singh9c58eba2016-09-02 16:23:06 +05303450 int ret = 0;
3451
Dustin Brown920397d2017-12-13 16:27:50 -08003452 hdd_for_each_adapter(hdd_ctx, adapter) {
jge62037862016-12-09 10:44:33 +08003453 if (adapter->device_mode == QDF_SAP_MODE) {
3454 hdd_ipa_uc_disconnect_client(adapter);
3455 hdd_ipa_uc_disconnect_ap(adapter);
3456 } else if (adapter->device_mode == QDF_STA_MODE) {
3457 hdd_ipa_uc_disconnect_sta(adapter);
3458 }
Govind Singh9c58eba2016-09-02 16:23:06 +05303459 }
3460
3461 return ret;
3462}
3463
3464/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003465 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003466 *
3467 * Deinit basic IPA UC host side to be in sync reloaded FW during
3468 * SSR
3469 *
3470 * Return: 0 - Success
3471 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003472static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003473{
3474 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3475 int idx;
3476 struct hdd_ipa_iface_context *iface_context;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003477 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003478
Yun Parke4239802018-01-09 11:01:40 -08003479 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003480
Arun Khandavallicc544b32017-01-30 19:52:16 +05303481 if (!hdd_ipa)
3482 return 0;
3483
3484 hdd_ctx = hdd_ipa->hdd_ctx;
3485 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003486 return 0;
3487
jge62037862016-12-09 10:44:33 +08003488 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303489 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003490
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003491 /* Clean up HDD IPA interfaces */
3492 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3493 (idx < HDD_IPA_MAX_IFACE); idx++) {
3494 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003495 if (iface_context->adapter && iface_context->adapter->magic ==
3496 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003497 hdd_ipa_cleanup_iface(iface_context);
3498 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003499 hdd_ipa->num_iface = 0;
Yun Parka4bb37c2017-12-08 16:14:22 -08003500
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003501 /* After SSR, wlan driver reloads FW again. But we need to protect
3502 * IPA submodule during SSR transient state. So deinit basic IPA
3503 * UC host side to be in sync with reloaded FW during SSR
3504 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003505
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303506 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003507 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3508 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3509 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3510 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303511 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003512
Guolei Bianca144d82016-11-10 11:07:42 +08003513 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3514 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3515
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003516 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
3517 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
3518 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
3519 hdd_ipa->uc_op_work[idx].msg = NULL;
3520 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003521
Yun Parke4239802018-01-09 11:01:40 -08003522 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003523 return 0;
3524}
3525
3526/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003527 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3528 *
3529 * Deinit basic IPA UC host side to be in sync reloaded FW during
3530 * SSR
3531 *
3532 * Return: 0 - Success
3533 */
3534int hdd_ipa_uc_ssr_deinit(void)
3535{
3536 int ret;
3537
3538 cds_ssr_protect(__func__);
3539 ret = __hdd_ipa_uc_ssr_deinit();
3540 cds_ssr_unprotect(__func__);
3541
3542 return ret;
3543}
3544
3545/**
3546 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003547 *
3548 * Init basic IPA UC host side to be in sync with reloaded FW after
3549 * SSR to resume IPA UC operations
3550 *
3551 * Return: 0 - Success
3552 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003553static int __hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003554{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003555
Arun Khandavallicc544b32017-01-30 19:52:16 +05303556 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3557 int i;
3558 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303559
Yun Parke4239802018-01-09 11:01:40 -08003560 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003561
Arun Khandavallicc544b32017-01-30 19:52:16 +05303562 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3563 return 0;
3564
Arun Khandavallicc544b32017-01-30 19:52:16 +05303565 /* Create the interface context */
3566 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3567 iface_context = &hdd_ipa->iface_context[i];
3568 iface_context->hdd_ipa = hdd_ipa;
3569 iface_context->cons_client =
3570 hdd_ipa_adapter_2_client[i].cons_client;
3571 iface_context->prod_client =
3572 hdd_ipa_adapter_2_client[i].prod_client;
3573 iface_context->iface_id = i;
3574 iface_context->adapter = NULL;
3575 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05303576
3577 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3578 hdd_ipa->resource_loading = false;
3579 hdd_ipa->resource_unloading = false;
3580 hdd_ipa->sta_connected = 0;
3581 hdd_ipa->ipa_pipes_down = true;
3582 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303583 }
3584
Yun Parke4239802018-01-09 11:01:40 -08003585 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003586 return 0;
3587}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003588
3589/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003590 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3591 *
3592 * Init basic IPA UC host side to be in sync with reloaded FW after
3593 * SSR to resume IPA UC operations
3594 *
3595 * Return: 0 - Success
3596 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003597int hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003598{
3599 int ret;
3600
3601 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303602 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003603 cds_ssr_unprotect(__func__);
3604
3605 return ret;
3606}
3607
3608/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003609 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3610 * @work: scheduled work
3611 *
3612 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3613 * not want to immediately release the wake lock since the system
3614 * would then potentially try to suspend when there is a healthy data
3615 * rate. Deferred work is scheduled and this function handles the
3616 * work. When this function is called, if the IPA resource is still
3617 * released then we release the wake lock.
3618 *
3619 * Return: None
3620 */
3621static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3622{
3623 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3624 struct hdd_ipa_priv,
3625 wake_lock_work);
3626
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303627 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003628
3629 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3630 goto end;
3631
3632 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303633 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003634 WIFI_POWER_EVENT_WAKELOCK_IPA);
3635
3636end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303637 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638}
3639
3640/**
3641 * hdd_ipa_rm_request() - Request resource from IPA
3642 * @hdd_ipa: Global HDD IPA context
3643 *
3644 * Return: 0 on success, negative errno on error
3645 */
3646static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3647{
3648 int ret = 0;
3649
3650 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3651 return 0;
3652
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303653 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003654
3655 switch (hdd_ipa->rm_state) {
3656 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303657 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658 return 0;
3659 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303660 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003661 return -EINPROGRESS;
3662 case HDD_IPA_RM_RELEASED:
3663 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3664 break;
3665 }
3666
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303667 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003668
Yun Park6c86a662017-10-05 16:09:15 -07003669 ret = qdf_ipa_rm_inactivity_timer_request_resource(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003670 IPA_RM_RESOURCE_WLAN_PROD);
3671
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303672 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003673 if (ret == 0) {
3674 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3675 hdd_ipa->stats.num_rm_grant_imm++;
3676 }
3677
3678 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3679 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303680 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003681 WIFI_POWER_EVENT_WAKELOCK_IPA);
3682 hdd_ipa->wake_lock_released = false;
3683 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303684 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003685
3686 return ret;
3687}
3688
3689/**
3690 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3691 * @hdd_ipa: Global HDD IPA context
3692 *
3693 * Return: 0 if resources released, negative errno otherwise
3694 */
3695static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3696{
3697 int ret = 0;
3698
3699 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3700 return 0;
3701
3702 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3703 return -EAGAIN;
3704
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303705 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003706
Nirav Shahcbc6d722016-03-01 16:24:53 +05303707 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303708 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003709 return -EAGAIN;
3710 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303711 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003712
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303713 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003714 switch (hdd_ipa->rm_state) {
3715 case HDD_IPA_RM_GRANTED:
3716 break;
3717 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303718 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003719 return -EINPROGRESS;
3720 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303721 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003722 return 0;
3723 }
3724
3725 /* IPA driver returns immediately so set the state here to avoid any
3726 * race condition.
3727 */
3728 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3729 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303730 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731
Yun Park6c86a662017-10-05 16:09:15 -07003732 ret = qdf_ipa_rm_inactivity_timer_release_resource(
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003733 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003734
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303735 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003736 if (unlikely(ret != 0)) {
3737 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3738 WARN_ON(1);
Yun Park199c2ed2017-10-02 11:24:22 -07003739 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
3740 "ipa_rm_inactivity_timer_release_resource returnied fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003741 }
3742
3743 /*
3744 * If wake_lock is released immediately, kernel would try to suspend
3745 * immediately as well, Just avoid ping-pong between suspend-resume
3746 * while there is healthy amount of data transfer going on by
3747 * releasing the wake_lock after some delay.
3748 */
3749 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3750 msecs_to_jiffies
3751 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3752
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303753 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003754
3755 return ret;
3756}
3757
3758/**
3759 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3760 * @user_data: user data registered with IPA
3761 * @event: the IPA resource manager event that occurred
3762 * @data: the data associated with the event
3763 *
3764 * Return: None
3765 */
Yun Park6c86a662017-10-05 16:09:15 -07003766static void hdd_ipa_rm_notify(void *user_data, qdf_ipa_rm_event_t event,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003767 unsigned long data)
3768{
3769 struct hdd_ipa_priv *hdd_ipa = user_data;
3770
3771 if (unlikely(!hdd_ipa))
3772 return;
3773
3774 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3775 return;
3776
Srinivas Girigowda97852372017-03-06 16:52:59 -08003777 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003778
3779 switch (event) {
3780 case IPA_RM_RESOURCE_GRANTED:
3781 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3782 /* RM Notification comes with ISR context
3783 * it should be serialized into work queue to avoid
3784 * ISR sleep problem
3785 */
3786 hdd_ipa->uc_rm_work.event = event;
3787 schedule_work(&hdd_ipa->uc_rm_work.work);
3788 break;
3789 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303790 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003791 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303792 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003793 hdd_ipa->stats.num_rm_grant++;
3794 break;
3795
3796 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003797 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003798 hdd_ipa->resource_unloading = false;
3799 break;
3800
3801 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303802 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003803 break;
3804 }
3805}
3806
3807/**
3808 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3809 *
3810 * Callback function registered with IPA that is called when IPA wants
3811 * to release the WLAN consumer resource
3812 *
3813 * Return: 0 if the request is granted, negative errno otherwise
3814 */
3815static int hdd_ipa_rm_cons_release(void)
3816{
3817 return 0;
3818}
3819
3820/**
3821 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3822 *
3823 * Callback function registered with IPA that is called when IPA wants
3824 * to access the WLAN consumer resource
3825 *
3826 * Return: 0 if the request is granted, negative errno otherwise
3827 */
3828static int hdd_ipa_rm_cons_request(void)
3829{
Yun Park4d8b60a2015-10-22 13:59:32 -07003830 int ret = 0;
3831
3832 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303833 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003834 "IPA resource loading in progress");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003835 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003836 ret = -EINPROGRESS;
3837 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303838 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003839 "IPA resource unloading in progress");
Yun Park4d8b60a2015-10-22 13:59:32 -07003840 ghdd_ipa->pending_cons_req = true;
3841 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003842 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003843
3844 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003845}
3846
3847/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003848 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003849 * @hdd_ctx: Global HDD context
3850 * @tx_packets: Number of packets transmitted in the last sample period
3851 * @rx_packets: Number of packets received in the last sample period
3852 *
3853 * Return: 0 on success, negative errno on error
3854 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07003855static int __hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx,
3856 uint64_t tx_packets,
3857 uint64_t rx_packets)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858{
3859 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003860 struct hdd_ipa_priv *hdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07003861 qdf_ipa_rm_perf_profile_t profile;
Yun Parkb4f591d2017-03-29 15:51:01 -07003862 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003863 int ret;
3864
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003865 if (wlan_hdd_validate_context(hdd_ctx))
3866 return 0;
3867
3868 hdd_ipa = hdd_ctx->hdd_ipa;
3869
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003870 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3871 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3872 return 0;
3873
3874 memset(&profile, 0, sizeof(profile));
3875
3876 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3877 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3878 else if (tx_packets >
3879 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3880 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3881 else
3882 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3883
3884 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3885 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3886 else if (rx_packets >
3887 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3888 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3889 else
3890 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3891
Yun Parkec845302016-12-15 09:22:57 -08003892 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003893 "CONS perf curr: %d, next: %d",
3894 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003895 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003896 "PROD perf curr: %d, next: %d",
3897 hdd_ipa->curr_prod_bw, next_prod_bw);
3898
3899 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003900 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003901 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003902 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS,
3903 next_cons_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003904 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003905 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003906
3907 return ret;
3908 }
3909 hdd_ipa->curr_cons_bw = next_cons_bw;
3910 hdd_ipa->stats.num_cons_perf_req++;
3911 }
3912
3913 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003914 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003915 hdd_ipa->curr_prod_bw, next_prod_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003916 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD,
3917 next_prod_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003919 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003920 return ret;
3921 }
3922 hdd_ipa->curr_prod_bw = next_prod_bw;
3923 hdd_ipa->stats.num_prod_perf_req++;
3924 }
3925
3926 return 0;
3927}
3928
3929/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003930 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3931 * @hdd_ctx: Global HDD context
3932 * @tx_packets: Number of packets transmitted in the last sample period
3933 * @rx_packets: Number of packets received in the last sample period
3934 *
3935 * Return: 0 on success, negative errno on error
3936 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003937int hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003938 uint64_t rx_packets)
3939{
3940 int ret;
3941
3942 cds_ssr_protect(__func__);
3943 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3944 cds_ssr_unprotect(__func__);
3945
3946 return ret;
3947}
3948
3949/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003950 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3951 * @work: struct work_struct
3952 * @work_handler: work_handler
3953 *
3954 * Return: none
3955 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003956static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3957 work_func_t work_handler)
3958{
3959 INIT_WORK(work, work_handler);
3960}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003961
3962/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003963 * hdd_ipa_setup_rm() - Setup IPA resource management
3964 * @hdd_ipa: Global HDD IPA context
3965 *
3966 * Return: 0 on success, negative errno on error
3967 */
3968static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3969{
Yun Park6c86a662017-10-05 16:09:15 -07003970 qdf_ipa_rm_create_params_t create_params = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003971 int ret;
3972
3973 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3974 return 0;
3975
Rajeev Kumar217f2172016-01-06 18:11:55 -08003976 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3977 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003978 memset(&create_params, 0, sizeof(create_params));
Yun Park6c86a662017-10-05 16:09:15 -07003979 QDF_IPA_RM_CREATE_PARAMS_NAME(&create_params) =
3980 IPA_RM_RESOURCE_WLAN_PROD;
3981 QDF_IPA_RM_CREATE_PARAMS_USER_DATA(&create_params) =
3982 hdd_ipa;
3983 QDF_IPA_RM_CREATE_PARAMS_NOTIFY_CB(&create_params) =
3984 hdd_ipa_rm_notify;
3985 QDF_IPA_RM_CREATE_PARAMS_FLOOR_VOLTAGE(&create_params) =
3986 IPA_VOLTAGE_SVS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003987
Yun Park6c86a662017-10-05 16:09:15 -07003988 ret = qdf_ipa_rm_create_resource(&create_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003989 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303990 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003991 "Create RM resource failed: %d", ret);
3992 goto setup_rm_fail;
3993 }
3994
3995 memset(&create_params, 0, sizeof(create_params));
Yun Park6c86a662017-10-05 16:09:15 -07003996 QDF_IPA_RM_CREATE_PARAMS_NAME(&create_params) =
3997 IPA_RM_RESOURCE_WLAN_CONS;
3998 QDF_IPA_RM_CREATE_PARAMS_REQUEST_RESOURCE(&create_params) =
3999 hdd_ipa_rm_cons_request;
4000 QDF_IPA_RM_CREATE_PARAMS_RELEASE_RESOURCE(&create_params) =
4001 hdd_ipa_rm_cons_release;
4002 QDF_IPA_RM_CREATE_PARAMS_FLOOR_VOLTAGE(&create_params) =
4003 IPA_VOLTAGE_SVS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004004
Yun Park6c86a662017-10-05 16:09:15 -07004005 ret = qdf_ipa_rm_create_resource(&create_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004006 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304007 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004008 "Create RM CONS resource failed: %d", ret);
4009 goto delete_prod;
4010 }
4011
4012 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
4013 IPA_RM_RESOURCE_APPS_CONS);
4014
Yun Park6c86a662017-10-05 16:09:15 -07004015 ret = qdf_ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
4016 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004017 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304018 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004019 ret);
4020 goto timer_init_failed;
4021 }
4022
4023 /* Set the lowest bandwidth to start with */
4024 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
4025
4026 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304027 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028 "Set perf level failed: %d", ret);
4029 goto set_perf_failed;
4030 }
4031
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304032 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004033 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
4034 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304035 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004036 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
4037 hdd_ipa->wake_lock_released = true;
4038 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
4039
4040 return ret;
4041
4042set_perf_failed:
4043 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4044
4045timer_init_failed:
4046 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4047
4048delete_prod:
4049 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4050
4051setup_rm_fail:
4052 return ret;
4053}
4054
4055/**
4056 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
4057 * @hdd_ipa: Global HDD IPA context
4058 *
4059 * Destroys all resources associated with the IPA resource manager
4060 *
4061 * Return: None
4062 */
4063static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
4064{
4065 int ret;
4066
4067 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4068 return;
4069
4070 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304071 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004072
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004073 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304074 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004075
4076 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4077
Yun Park6c86a662017-10-05 16:09:15 -07004078 ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004079 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304080 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004081 "RM PROD resource delete failed %d", ret);
4082
Yun Park6c86a662017-10-05 16:09:15 -07004083 ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004084 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304085 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004086 "RM CONS resource delete failed %d", ret);
4087}
4088
tfyu0380a972017-07-13 18:19:37 +08004089#ifdef QCA_CONFIG_SMP
4090static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4091{
4092 return netif_rx_ni(skb);
4093}
4094#else
4095static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4096{
4097 struct iphdr *ip_h;
4098 static atomic_t softirq_mitigation_cntr =
4099 ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH);
4100 int result;
4101
4102 ip_h = (struct iphdr *)(skb->data);
4103 if ((skb->protocol == htons(ETH_P_IP)) &&
4104 (ip_h->protocol == IPPROTO_ICMP)) {
4105 result = netif_rx_ni(skb);
4106 } else {
4107 /* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets
4108 * to avoid excessive softirq's.
4109 */
4110 if (atomic_dec_and_test(&softirq_mitigation_cntr)) {
4111 result = netif_rx_ni(skb);
4112 atomic_set(&softirq_mitigation_cntr,
4113 IPA_WLAN_RX_SOFTIRQ_THRESH);
4114 } else {
4115 result = netif_rx(skb);
4116 }
4117 }
4118
4119 return result;
4120}
4121#endif
4122
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004123/**
4124 * hdd_ipa_send_skb_to_network() - Send skb to kernel
4125 * @skb: network buffer
4126 * @adapter: network adapter
4127 *
4128 * Called when a network buffer is received which should not be routed
4129 * to the IPA module.
4130 *
4131 * Return: None
4132 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304133static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004134 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004135{
tfyu0380a972017-07-13 18:19:37 +08004136 int result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004137 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4138 unsigned int cpu_index;
4139
4140 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Jeff Johnson36e74c42017-09-18 08:15:42 -07004141 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%pK",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004142 adapter);
Yun Park46255682017-10-09 15:56:34 -07004143 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004144 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004145 return;
4146 }
4147
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004148 if (cds_is_driver_unloading()) {
Yun Park46255682017-10-09 15:56:34 -07004149 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004150 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004151 return;
4152 }
4153
4154 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
4155 skb->dev = adapter->dev;
4156 skb->protocol = eth_type_trans(skb, skb->dev);
4157 skb->ip_summed = CHECKSUM_NONE;
4158
4159 cpu_index = wlan_hdd_get_cpu();
4160
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004161 ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index];
tfyu0380a972017-07-13 18:19:37 +08004162 result = hdd_ipa_aggregated_rx_ind(skb);
4163 if (result == NET_RX_SUCCESS)
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004164 ++adapter->hdd_stats.tx_rx_stats.rx_delivered[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004165 else
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004166 ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004167
Yun Park46255682017-10-09 15:56:34 -07004168 hdd_ipa->ipa_rx_net_send_count++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004169}
4170
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004171/**
Leo Chang69c39692016-10-12 20:11:12 -07004172 * hdd_ipa_forward() - handle packet forwarding to wlan tx
4173 * @hdd_ipa: pointer to hdd ipa context
4174 * @adapter: network adapter
4175 * @skb: data pointer
4176 *
4177 * if exception packet has set forward bit, copied new packet should be
4178 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
4179 * put into pm queue and tx procedure will be differed
4180 *
4181 * Return: None
4182 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07004183static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004184 struct hdd_adapter *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07004185{
Leo Chang69c39692016-10-12 20:11:12 -07004186 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
4187
Leo Chang69c39692016-10-12 20:11:12 -07004188 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Yun Park01deb2c2017-06-14 15:21:44 -07004189
4190 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
4191 qdf_nbuf_ipa_owned_set(skb);
4192
Yun Park46255682017-10-09 15:56:34 -07004193 /* WLAN subsystem is in suspend, put in queue */
Leo Chang69c39692016-10-12 20:11:12 -07004194 if (hdd_ipa->suspended) {
4195 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Yun Park46255682017-10-09 15:56:34 -07004196 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4197 "Tx in suspend, put in queue");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004198 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
4199 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07004200 pm_tx_cb->exception = true;
4201 pm_tx_cb->adapter = adapter;
4202 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004203 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07004204 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4205 hdd_ipa->stats.num_tx_queued++;
4206 } else {
4207 /* Resume, put packet into WLAN TX */
4208 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004209 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07004210 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07004211 "packet Tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08004212 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07004213 } else {
Yun Parkb187d542016-11-14 18:10:04 -08004214 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07004215 }
4216 }
4217}
4218
4219/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004220 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
4221 * @hdd_ipa: pointer to HDD IPA struct
4222 * @adapter: hdd adapter pointer
4223 * @desc: Firmware descriptor
4224 * @skb: Data buffer
4225 *
4226 * Return:
4227 * HDD_IPA_FORWARD_PKT_NONE
4228 * HDD_IPA_FORWARD_PKT_DISCARD
4229 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
4230 *
4231 */
4232
4233static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
4234 struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004235 struct hdd_adapter *adapter,
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004236 uint8_t desc,
4237 qdf_nbuf_t skb)
4238{
4239 int ret = HDD_IPA_FORWARD_PKT_NONE;
Yun Park0dad1002017-07-14 14:57:01 -07004240 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
4241 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004242
4243 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304244 if (!ol_txrx_fwd_desc_thresh_check(
Yun Park0dad1002017-07-14 14:57:01 -07004245 (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc,
4246 (struct cdp_pdev *)pdev,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004247 adapter->session_id))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304248 /* Drop the packet*/
4249 hdd_ipa->stats.num_tx_fwd_err++;
4250 kfree_skb(skb);
4251 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4252 return ret;
4253 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004254 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
4255 "Forward packet to Tx (fw_desc=%d)", desc);
4256 hdd_ipa->ipa_tx_forward++;
4257
4258 if ((desc & FW_RX_DESC_DISCARD_M)) {
4259 hdd_ipa_forward(hdd_ipa, adapter, skb);
Yun Park46255682017-10-09 15:56:34 -07004260 hdd_ipa->ipa_rx_internal_drop_count++;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004261 hdd_ipa->ipa_rx_discard++;
4262 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4263 } else {
4264 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004265
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004266 if (cloned_skb)
4267 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
4268 else
4269 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07004270 "tx skb alloc failed");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004271 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
4272 }
4273 }
4274
4275 return ret;
4276}
4277
4278/**
Yun Park637d6482016-10-05 10:51:33 -07004279 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 * @priv: pointer to private data registered with IPA (we register a
4281 * pointer to the global IPA context)
4282 * @evt: the IPA event which triggered the callback
4283 * @data: data associated with the event
4284 *
4285 * Return: None
4286 */
Yun Park6c86a662017-10-05 16:09:15 -07004287static void __hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
4288 unsigned long data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004289{
4290 struct hdd_ipa_priv *hdd_ipa = NULL;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004291 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304292 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293 uint8_t iface_id;
4294 uint8_t session_id;
4295 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004296 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07004297 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004298
4299 hdd_ipa = (struct hdd_ipa_priv *)priv;
4300
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08004301 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
4302 return;
4303
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004304 switch (evt) {
4305 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05304306 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07004307
4308 /*
4309 * When SSR is going on or driver is unloading,
4310 * just drop the packets.
4311 */
4312 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4313 if (0 != status) {
4314 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4315 "Invalid context: drop packet");
Yun Park46255682017-10-09 15:56:34 -07004316 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004317 kfree_skb(skb);
4318 return;
4319 }
4320
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004321 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4322 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004323 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004324 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004325 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4326 session_id, iface_id);
4327 } else {
4328 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4329 }
4330
4331 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304332 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004333 "IPA_RECEIVE: Invalid iface_id: %u",
4334 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004335 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004336 "w2i -- skb",
4337 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Yun Park46255682017-10-09 15:56:34 -07004338 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004339 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 return;
4341 }
4342
4343 iface_context = &hdd_ipa->iface_context[iface_id];
4344 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08004345 if (!adapter) {
4346 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4347 "IPA_RECEIVE: Adapter is NULL");
Yun Park46255682017-10-09 15:56:34 -07004348 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Park16a78262017-02-01 12:15:03 -08004349 kfree_skb(skb);
4350 return;
4351 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004352
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304353 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004354 "w2i -- skb",
4355 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004356 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4357 hdd_ipa->stats.num_rx_excep++;
4358 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4359 } else {
4360 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4361 }
4362
4363 iface_context->stats.num_rx_ipa_excep++;
4364
4365 /* Disable to forward Intra-BSS Rx packets when
4366 * ap_isolate=1 in hostapd.conf
4367 */
Jeff Johnsonb9424862017-10-30 08:49:35 -07004368 if (!adapter->session.ap.disable_intrabss_fwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004369 /*
4370 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4371 * all Rx packets to IPA uC, which need to be forwarded
4372 * to other interface.
4373 * And, IPA driver will send back to WLAN host driver
4374 * through exception pipe with fw_desc field set by FW.
4375 * Here we are checking fw_desc field for FORWARD bit
4376 * set, and forward to Tx. Then copy to kernel stack
4377 * only when DISCARD bit is not set.
4378 */
4379 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004380 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4381 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4382 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004383 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004384 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004385 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386 "Intra-BSS FWD is disabled-skip forward to Tx");
4387 }
4388
4389 hdd_ipa_send_skb_to_network(skb, adapter);
4390 break;
4391
4392 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304393 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004394 "w2i cb wrong event: 0x%x", evt);
4395 return;
4396 }
4397}
4398
4399/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004400 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4401 * @priv: pointer to private data registered with IPA (we register a
4402 * pointer to the global IPA context)
4403 * @evt: the IPA event which triggered the callback
4404 * @data: data associated with the event
4405 *
4406 * Return: None
4407 */
Yun Park6c86a662017-10-05 16:09:15 -07004408static void hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Yun Parkf8d6a122016-10-11 15:49:43 -07004409 unsigned long data)
4410{
4411 cds_ssr_protect(__func__);
4412 __hdd_ipa_w2i_cb(priv, evt, data);
4413 cds_ssr_unprotect(__func__);
4414}
4415
4416/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4418 * @skb: packet buffer which was transmitted
4419 *
4420 * Return: None
4421 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304422void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423{
4424 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07004425 qdf_ipa_rx_data_t *ipa_tx_desc;
Yun Park52b2b992016-09-22 15:49:51 -07004426 struct hdd_ipa_tx_desc *tx_desc;
4427 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004428
Yun Park52b2b992016-09-22 15:49:51 -07004429 if (!qdf_nbuf_ipa_owned_get(skb)) {
4430 dev_kfree_skb_any(skb);
4431 return;
4432 }
4433
4434 /* Get Tx desc pointer from SKB CB */
4435 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4436 tx_desc = hdd_ipa->tx_desc_list + id;
4437 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4438
4439 /* Return Tx Desc to IPA */
4440 ipa_free_skb(ipa_tx_desc);
4441
4442 /* Return to free tx desc list */
4443 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4444 tx_desc->ipa_tx_desc_ptr = NULL;
4445 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4446 hdd_ipa->stats.num_tx_desc_q_cnt--;
4447 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004448
4449 hdd_ipa->stats.num_tx_comp_cnt++;
4450
4451 atomic_dec(&hdd_ipa->tx_ref_cnt);
4452
4453 hdd_ipa_rm_try_release(hdd_ipa);
4454}
4455
4456/**
4457 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4458 * @iface_context: interface-specific IPA context
4459 * @ipa_tx_desc: packet data descriptor
4460 *
4461 * Return: None
4462 */
4463static void hdd_ipa_send_pkt_to_tl(
4464 struct hdd_ipa_iface_context *iface_context,
Yun Park6c86a662017-10-05 16:09:15 -07004465 qdf_ipa_rx_data_t *ipa_tx_desc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004466{
4467 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004468 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304469 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004470 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304472 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004473 adapter = iface_context->adapter;
4474 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304475 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004476 ipa_free_skb(ipa_tx_desc);
4477 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304478 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004479 hdd_ipa_rm_try_release(hdd_ipa);
4480 return;
4481 }
4482
4483 /*
4484 * During CAC period, data packets shouldn't be sent over the air so
4485 * drop all the packets here
4486 */
hqu70708ab2017-10-10 17:52:01 +08004487 if (QDF_SAP_MODE == adapter->device_mode ||
4488 QDF_P2P_GO_MODE == adapter->device_mode) {
4489 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4490 ipa_free_skb(ipa_tx_desc);
4491 qdf_spin_unlock_bh(&iface_context->interface_lock);
4492 iface_context->stats.num_tx_cac_drop++;
4493 hdd_ipa_rm_try_release(hdd_ipa);
4494 return;
4495 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004496 }
4497
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498 ++adapter->stats.tx_packets;
4499
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304500 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004501
Yun Park6c86a662017-10-05 16:09:15 -07004502 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004503
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304504 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004505
4506 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304507 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004508 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304509 qdf_nbuf_mapped_paddr_set(skb,
Yun Park6c86a662017-10-05 16:09:15 -07004510 QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc)
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004511 + HDD_IPA_WLAN_FRAG_HEADER
4512 + HDD_IPA_WLAN_IPA_HEADER);
Yun Park6c86a662017-10-05 16:09:15 -07004513 QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004514 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4515 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304516 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004517
Yun Park52b2b992016-09-22 15:49:51 -07004518 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4519 /* get free Tx desc and assign ipa_tx_desc pointer */
4520 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4521 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4522 struct hdd_ipa_tx_desc, link);
4523 list_del(&tx_desc->link);
4524 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4525 hdd_ipa->stats.num_tx_desc_q_cnt++;
4526 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4527 /* Store Tx Desc index into SKB CB */
4528 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4529 } else {
4530 hdd_ipa->stats.num_tx_desc_error++;
4531 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Yun Park52b2b992016-09-22 15:49:51 -07004532 ipa_free_skb(ipa_tx_desc);
4533 hdd_ipa_rm_try_release(hdd_ipa);
4534 return;
4535 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004536
Yun Park6c86a662017-10-05 16:09:15 -07004537 adapter->stats.tx_bytes += QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004538
Leo Changfdb45c32016-10-28 11:09:23 -07004539 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Yun Park6c86a662017-10-05 16:09:15 -07004540 (struct cdp_vdev *)iface_context->tl_context,
4541 QDF_IPA_RX_DATA_SKB(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004542 if (skb) {
jiad05c1e812017-08-01 16:48:52 +08004543 qdf_nbuf_free(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004544 iface_context->stats.num_tx_err++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004545 return;
4546 }
4547
4548 atomic_inc(&hdd_ipa->tx_ref_cnt);
4549
4550 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004551}
4552
4553/**
Leo Chang11545d62016-10-17 14:53:50 -07004554 * hdd_ipa_is_present() - get IPA hw status
4555 * @hdd_ctx: pointer to hdd context
4556 *
4557 * ipa_uc_reg_rdyCB is not directly designed to check
4558 * ipa hw status. This is an undocumented function which
4559 * has confirmed with IPA team.
4560 *
4561 * Return: true - ipa hw present
4562 * false - ipa hw not present
4563 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004564bool hdd_ipa_is_present(struct hdd_context *hdd_ctx)
Leo Chang11545d62016-10-17 14:53:50 -07004565{
jiad4ab698b2018-02-02 13:43:09 +08004566 /*
4567 * Check if ipa hw is enabled
4568 * TODO: Add support for WDI unified API
4569 */
4570 if (ipa_uc_reg_rdyCB(NULL) != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004571 return true;
4572 else
4573 return false;
4574}
4575
4576/**
Leo Chang69c39692016-10-12 20:11:12 -07004577 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004578 * @work: pointer to the scheduled work
4579 *
4580 * Called during PM resume to send packets to TL which were queued
4581 * while host was in the process of suspending.
4582 *
4583 * Return: None
4584 */
Leo Chang69c39692016-10-12 20:11:12 -07004585static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004586{
4587 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4588 struct hdd_ipa_priv,
4589 pm_work);
4590 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304591 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004592 uint32_t dequeued = 0;
4593
Leo Chang69c39692016-10-12 20:11:12 -07004594 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4595 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304596 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304597 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4598 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304599 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004600
4601 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004602 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004603 if (pm_tx_cb->exception) {
Yun Park46255682017-10-09 15:56:34 -07004604 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4605 "Flush Exception");
Govind Singh1dab23b2017-08-12 13:31:00 +05304606 if (pm_tx_cb->adapter->dev)
4607 hdd_softap_hard_start_xmit(skb,
4608 pm_tx_cb->adapter->dev);
Govind Singh02075942017-08-15 11:13:28 +05304609 else
4610 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004611 } else {
4612 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004614 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304615 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004616 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304617 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004618 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4619 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004620
4621 hdd_ipa->stats.num_tx_dequeued += dequeued;
4622 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4623 hdd_ipa->stats.num_max_pm_queue = dequeued;
4624}
4625
4626/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004627 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004628 * @priv: pointer to private data registered with IPA (we register a
4629 * pointer to the interface-specific IPA context)
4630 * @evt: the IPA event which triggered the callback
4631 * @data: data associated with the event
4632 *
4633 * Return: None
4634 */
Yun Park6c86a662017-10-05 16:09:15 -07004635static void __hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
4636 unsigned long data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637{
4638 struct hdd_ipa_priv *hdd_ipa = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07004639 qdf_ipa_rx_data_t *ipa_tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304641 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004642 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304643 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644
Mukul Sharma81661ae2015-10-30 20:26:02 +05304645 iface_context = (struct hdd_ipa_iface_context *)priv;
Yun Park6c86a662017-10-05 16:09:15 -07004646 ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004647 hdd_ipa = iface_context->hdd_ipa;
4648
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004649 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004650 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4651 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004652 iface_context->stats.num_tx_drop++;
4653 return;
4654 }
4655
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004656 /*
4657 * When SSR is going on or driver is unloading, just drop the packets.
4658 * During SSR, there is no use in queueing the packets as STA has to
4659 * connect back any way
4660 */
4661 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304662 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004663 ipa_free_skb(ipa_tx_desc);
4664 iface_context->stats.num_tx_drop++;
4665 return;
4666 }
4667
Yun Park6c86a662017-10-05 16:09:15 -07004668 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669
Yun Parkb187d542016-11-14 18:10:04 -08004670 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4671 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004672
4673 /*
4674 * If PROD resource is not requested here then there may be cases where
4675 * IPA hardware may be clocked down because of not having proper
4676 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4677 * workaround to request PROD resource while data is going over CONS
4678 * pipe to prevent the IPA hardware clockdown.
4679 */
4680 hdd_ipa_rm_request(hdd_ipa);
4681
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304682 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004683 /*
4684 * If host is still suspended then queue the packets and these will be
4685 * drained later when resume completes. When packet is arrived here and
4686 * host is suspended, this means that there is already resume is in
4687 * progress.
4688 */
4689 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304690 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004691 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4692 pm_tx_cb->iface_context = iface_context;
4693 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304694 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004695 hdd_ipa->stats.num_tx_queued++;
4696
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304697 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004698 return;
4699 }
4700
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304701 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004702
4703 /*
4704 * If we are here means, host is not suspended, wait for the work queue
4705 * to finish.
4706 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004707 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004708
4709 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4710}
4711
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004712/*
4713 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4714 * @priv: pointer to private data registered with IPA (we register a
4715 * pointer to the interface-specific IPA context)
4716 * @evt: the IPA event which triggered the callback
4717 * @data: data associated with the event
4718 *
4719 * Return: None
4720 */
Yun Park6c86a662017-10-05 16:09:15 -07004721static void hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004722 unsigned long data)
4723{
4724 cds_ssr_protect(__func__);
4725 __hdd_ipa_i2w_cb(priv, evt, data);
4726 cds_ssr_unprotect(__func__);
4727}
4728
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004729/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004730 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004731 * @hdd_ctx: Global HDD context
4732 *
4733 * Return: 0 on success, negativer errno on error
4734 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004735static int __hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004736{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004737 struct hdd_ipa_priv *hdd_ipa;
4738
4739 if (wlan_hdd_validate_context(hdd_ctx))
4740 return 0;
4741
4742 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004743
4744 if (!hdd_ipa_is_enabled(hdd_ctx))
4745 return 0;
4746
4747 /*
4748 * Check if IPA is ready for suspend, If we are here means, there is
4749 * high chance that suspend would go through but just to avoid any race
4750 * condition after suspend started, these checks are conducted before
4751 * allowing to suspend.
4752 */
4753 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4754 return -EAGAIN;
4755
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304756 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004757
4758 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304759 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004760 return -EAGAIN;
4761 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304762 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004763
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304764 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004765 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304766 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004767
4768 return 0;
4769}
4770
4771/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004772 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4773 * @hdd_ctx: Global HDD context
4774 *
4775 * Return: 0 on success, negativer errno on error
4776 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004777int hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004778{
4779 int ret;
4780
4781 cds_ssr_protect(__func__);
4782 ret = __hdd_ipa_suspend(hdd_ctx);
4783 cds_ssr_unprotect(__func__);
4784
4785 return ret;
4786}
4787
4788/**
4789 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004790 * hdd_ctx: Global HDD context
4791 *
4792 * Return: 0 on success, negative errno on error
4793 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004794static int __hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004795{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004796 struct hdd_ipa_priv *hdd_ipa;
4797
4798 if (wlan_hdd_validate_context(hdd_ctx))
4799 return 0;
4800
4801 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004802
4803 if (!hdd_ipa_is_enabled(hdd_ctx))
4804 return 0;
4805
4806 schedule_work(&hdd_ipa->pm_work);
4807
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304808 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004809 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304810 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004811
4812 return 0;
4813}
4814
4815/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004816 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4817 * hdd_ctx: Global HDD context
4818 *
4819 * Return: 0 on success, negative errno on error
4820 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004821int hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004822{
4823 int ret;
4824
4825 cds_ssr_protect(__func__);
4826 ret = __hdd_ipa_resume(hdd_ctx);
4827 cds_ssr_unprotect(__func__);
4828
4829 return ret;
4830}
4831
4832/**
Yun Park52b2b992016-09-22 15:49:51 -07004833 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
4834 * @hdd_ipa: Global HDD IPA context
4835 *
4836 * Return: 0 on success, negative errno on error
4837 */
4838static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
4839{
4840 int i;
4841 uint32_t max_desc_cnt;
4842 struct hdd_ipa_tx_desc *tmp_desc;
4843
Yun Parkd9c528e2017-08-30 16:34:57 -07004844 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
Yun Park52b2b992016-09-22 15:49:51 -07004845
4846 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
4847
jiad14fe4fb2017-08-08 13:33:14 +08004848 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc) *
Yun Parkd9c528e2017-08-30 16:34:57 -07004849 max_desc_cnt);
Yun Park52b2b992016-09-22 15:49:51 -07004850
4851 if (!tmp_desc) {
4852 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkd9c528e2017-08-30 16:34:57 -07004853 "Free Tx descriptor allocation failed");
Yun Park52b2b992016-09-22 15:49:51 -07004854 return -ENOMEM;
4855 }
4856
4857 hdd_ipa->tx_desc_list = tmp_desc;
4858
4859 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07004860 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07004861 tmp_desc->id = i;
4862 tmp_desc->ipa_tx_desc_ptr = NULL;
4863 list_add_tail(&tmp_desc->link,
4864 &hdd_ipa->free_tx_desc_head);
4865 tmp_desc++;
4866 }
4867
4868 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4869 hdd_ipa->stats.num_tx_desc_error = 0;
4870
4871 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4872
4873 return 0;
4874}
4875
Yun Park9281cb72017-11-30 11:14:30 -08004876#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Yun Park52b2b992016-09-22 15:49:51 -07004877/**
Yun Park9281cb72017-11-30 11:14:30 -08004878 * hdd_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004879 * @hdd_ipa: Global HDD IPA context
Yun Park9281cb72017-11-30 11:14:30 -08004880 * @desc_fifo_sz: Number of descriptors
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004881 *
4882 * Return: 0 on success, negative errno on error
4883 */
Yun Park9281cb72017-11-30 11:14:30 -08004884static int hdd_ipa_setup_tx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
4885 int32_t desc_fifo_sz)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004886{
4887 int i, ret = 0;
Yun Park6c86a662017-10-05 16:09:15 -07004888 qdf_ipa_sys_connect_params_t *ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004889
4890 /*setup TX pipes */
4891 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4892 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4893
4894 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4895 ipa->desc_fifo_sz = desc_fifo_sz;
4896 ipa->priv = &hdd_ipa->iface_context[i];
4897 ipa->notify = hdd_ipa_i2w_cb;
4898
4899 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4900 ipa->ipa_ep_cfg.hdr.hdr_len =
4901 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4902 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4903 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4904 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4905 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4906 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4907 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4908 } else {
4909 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4910 }
4911 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4912
4913 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4914 ipa->keep_ipa_awake = 1;
4915
Yun Park6c86a662017-10-05 16:09:15 -07004916 ret = qdf_ipa_setup_sys_pipe(ipa,
4917 &hdd_ipa->sys_pipe[i].conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004918 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004919 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4920 "Failed for pipe %d ret: %d", i, ret);
Yun Park9281cb72017-11-30 11:14:30 -08004921 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004922 }
4923 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4924 }
4925
Yun Park9281cb72017-11-30 11:14:30 -08004926 return ret;
4927}
4928#else
4929/**
4930 * hdd_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
4931 * @hdd_ipa: Global HDD IPA context
4932 * @desc_fifo_sz: Number of descriptors
4933 *
4934 * Return: 0 on success, negative errno on error
4935 */
4936static int hdd_ipa_setup_tx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
4937 int32_t desc_fifo_sz)
4938{
4939 /*
4940 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
4941 * is enabled, where per vdev descriptors are supported in firmware.
4942 */
4943 return 0;
4944}
4945#endif
4946
4947/**
4948 * hdd_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
4949 * @hdd_ipa: Global HDD IPA context
4950 * @desc_fifo_sz: Number of descriptors
4951 *
4952 * Return: 0 on success, negative errno on error
4953 */
4954static int hdd_ipa_setup_rx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
4955 int32_t desc_fifo_sz)
4956{
4957 int ret = 0;
4958 qdf_ipa_sys_connect_params_t *ipa;
4959
4960 /*
4961 * Hard code it here, this can be extended if in case
4962 * PROD pipe is also per interface.
4963 * Right now there is no advantage of doing this.
4964 */
4965 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4966
4967 ipa->client = IPA_CLIENT_WLAN1_PROD;
4968
4969 ipa->desc_fifo_sz = desc_fifo_sz;
4970 ipa->priv = hdd_ipa;
4971 ipa->notify = hdd_ipa_w2i_cb;
4972
4973 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4974 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4975 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4976 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4977
4978 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4979 ipa->keep_ipa_awake = 1;
4980
4981 ret = qdf_ipa_setup_sys_pipe(ipa,
4982 &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl);
4983 if (ret) {
4984 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4985 "Failed for RX pipe: %d", ret);
4986 return ret;
4987 }
4988 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4989
4990 return ret;
4991}
4992
4993/**
4994 * hdd_ipa_setup_sys_pipe() - Setup all IPA system pipes
4995 * @hdd_ipa: Global HDD IPA context
4996 *
4997 * Return: 0 on success, negative errno on error
4998 */
4999static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
5000{
5001 int i = HDD_IPA_MAX_IFACE, ret = 0;
5002 uint32_t desc_fifo_sz;
5003
5004 /* The maximum number of descriptors that can be provided to a BAM at
5005 * once is one less than the total number of descriptors that the buffer
5006 * can contain.
5007 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
5008 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
5009 * be provided at once.
5010 * Because of above requirement, one extra descriptor will be added to
5011 * make sure hardware always has one descriptor.
5012 */
5013 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
Yuanyuan Liu23a8eec2017-12-15 16:01:12 -08005014 + SPS_DESC_SIZE;
Yun Park9281cb72017-11-30 11:14:30 -08005015
5016 ret = hdd_ipa_setup_tx_sys_pipe(hdd_ipa, desc_fifo_sz);
5017 if (ret) {
5018 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5019 "Failed for TX pipe: %d", ret);
5020 goto setup_sys_pipe_fail;
5021 }
5022
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005023 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park9281cb72017-11-30 11:14:30 -08005024 ret = hdd_ipa_setup_rx_sys_pipe(hdd_ipa, desc_fifo_sz);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005025 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305026 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park9281cb72017-11-30 11:14:30 -08005027 "Failed for RX pipe: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005028 goto setup_sys_pipe_fail;
5029 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005030 }
5031
Yun Parkd9c528e2017-08-30 16:34:57 -07005032 /* Allocate free Tx desc list */
Yun Park52b2b992016-09-22 15:49:51 -07005033 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
5034 if (ret)
5035 goto setup_sys_pipe_fail;
5036
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005037 return ret;
5038
5039setup_sys_pipe_fail:
5040
Yun Park9281cb72017-11-30 11:14:30 -08005041 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
5042 if (hdd_ipa->sys_pipe[i].conn_hdl_valid)
5043 qdf_ipa_teardown_sys_pipe(
5044 hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305045 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005046 sizeof(struct hdd_ipa_sys_pipe));
5047 }
5048
5049 return ret;
5050}
5051
5052/**
5053 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
5054 * @hdd_ipa: Global HDD IPA context
5055 *
5056 * Return: None
5057 */
5058static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
5059{
5060 int ret = 0, i;
Yun Parkd9c528e2017-08-30 16:34:57 -07005061 uint32_t max_desc_cnt;
Yun Park52b2b992016-09-22 15:49:51 -07005062 struct hdd_ipa_tx_desc *tmp_desc;
Yun Park6c86a662017-10-05 16:09:15 -07005063 qdf_ipa_rx_data_t *ipa_tx_desc;
Yun Park52b2b992016-09-22 15:49:51 -07005064
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005065 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
5066 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
Yun Park9281cb72017-11-30 11:14:30 -08005067 ret = qdf_ipa_teardown_sys_pipe(
5068 hdd_ipa->sys_pipe[i].conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005069 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305070 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005071 ret);
5072
5073 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
5074 }
5075 }
Yun Park52b2b992016-09-22 15:49:51 -07005076
5077 if (hdd_ipa->tx_desc_list) {
Yun Parkd9c528e2017-08-30 16:34:57 -07005078 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
5079
Yun Park52b2b992016-09-22 15:49:51 -07005080 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07005081 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07005082 tmp_desc = hdd_ipa->tx_desc_list + i;
5083 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
5084 if (ipa_tx_desc)
5085 ipa_free_skb(ipa_tx_desc);
5086 }
5087 tmp_desc = hdd_ipa->tx_desc_list;
5088 hdd_ipa->tx_desc_list = NULL;
5089 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
5090 hdd_ipa->stats.num_tx_desc_error = 0;
5091 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
5092 qdf_mem_free(tmp_desc);
5093 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005094}
5095
5096/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005097 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
5098 * @iface_context: interface-specific IPA context
5099 *
5100 * Return: None
5101 */
5102static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
5103{
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005104 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07005105
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005106 if (iface_context == NULL)
5107 return;
Orhan K AKYILDIZ3332be32017-05-31 15:36:31 -07005108 if (iface_context->adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
5109 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
5110 "%s: bad adapter(%pK).magic(%d)!",
5111 __func__, iface_context->adapter,
5112 iface_context->adapter->magic);
5113 return;
5114 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005115
Yun Parkb4f591d2017-03-29 15:51:01 -07005116 cdp_ipa_cleanup_iface(cds_get_context(QDF_MODULE_ID_SOC),
5117 iface_context->adapter->dev->name,
5118 hdd_ipa_is_ipv6_enabled(iface_context->hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005119
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305120 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005121 iface_context->adapter->ipa_context = NULL;
5122 iface_context->adapter = NULL;
5123 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305124 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005125 iface_context->ifa_address = 0;
5126 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305127 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005128 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05305129 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005130 }
5131 iface_context->hdd_ipa->num_iface--;
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005132 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005133 iface_context->hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005134}
5135
5136/**
5137 * hdd_ipa_setup_iface() - Setup IPA on a given interface
5138 * @hdd_ipa: HDD IPA global context
5139 * @adapter: Interface upon which IPA is being setup
5140 * @sta_id: Station ID of the API instance
5141 *
5142 * Return: 0 on success, negative errno value on error
5143 */
5144static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07005145 struct hdd_adapter *adapter, uint8_t sta_id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005146{
5147 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park0dad1002017-07-14 14:57:01 -07005148 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
5149 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005150 void *tl_context = NULL;
5151 int i, ret = 0;
5152
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005153 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07005154
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005155 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
5156 * channel change indication. Since these indications are sent by lower
5157 * layer as SAP updates and IPA doesn't have to do anything for these
5158 * updates so ignoring!
5159 */
Krunal Sonibe766b02016-03-10 13:00:44 -08005160 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005161 return 0;
5162
5163 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5164 if (hdd_ipa->iface_context[i].adapter == NULL) {
5165 iface_context = &(hdd_ipa->iface_context[i]);
5166 break;
5167 }
5168 }
5169
5170 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305171 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005172 "All the IPA interfaces are in use");
5173 ret = -ENOMEM;
5174 goto end;
5175 }
5176
5177 adapter->ipa_context = iface_context;
5178 iface_context->adapter = adapter;
5179 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08005180 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Yun Park0dad1002017-07-14 14:57:01 -07005181 soc, (struct cdp_pdev *)pdev, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005182 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305183 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005184 "Not able to get TL context sta_id: %d", sta_id);
5185 ret = -EINVAL;
5186 goto end;
5187 }
5188
5189 iface_context->tl_context = tl_context;
5190
Yun Parkb4f591d2017-03-29 15:51:01 -07005191 ret = cdp_ipa_setup_iface(cds_get_context(QDF_MODULE_ID_SOC),
5192 adapter->dev->name, adapter->dev->dev_addr,
5193 iface_context->prod_client,
5194 iface_context->cons_client,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005195 adapter->session_id,
Yun Parkb4f591d2017-03-29 15:51:01 -07005196 hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005197 if (ret)
5198 goto end;
5199
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005200 hdd_ipa->num_iface++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005201
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005202 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005203 hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005204 return ret;
5205
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005206end:
5207 if (iface_context)
5208 hdd_ipa_cleanup_iface(iface_context);
5209 return ret;
5210}
5211
Yun Parka27049a2016-10-11 12:30:49 -07005212#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005213/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005214 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Jeff Johnson4929cd92017-10-06 19:21:57 -07005215 * @hdd_ctx: HDD context
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005216 * @mcc_mode: 0=MCC/1=SCC
5217 *
5218 * Return: 0 on success, negative errno value on error
5219 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07005220static int __hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx,
5221 bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005222{
Jeff Johnson089d0432017-10-02 13:27:21 -07005223 struct hdd_adapter *adapter;
Yun Park6c86a662017-10-05 16:09:15 -07005224 qdf_ipa_msg_meta_t meta;
5225 qdf_ipa_wlan_msg_t *msg;
5226
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005227 int ret;
5228
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005229 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005230 return -EINVAL;
5231
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005232 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
5233 return -EINVAL;
5234
5235 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005236 /* Flush TxRx queue for each adapter before switch to SCC */
Dustin Brown920397d2017-12-13 16:27:50 -08005237 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson089d0432017-10-02 13:27:21 -07005238 if (adapter->device_mode == QDF_STA_MODE ||
5239 adapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005240 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnson089d0432017-10-02 13:27:21 -07005241 adapter->device_mode);
5242 hdd_deinit_tx_rx(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005243 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005244 }
5245 }
5246
5247 /* Send SCC/MCC Switching event to IPA */
Yun Park6c86a662017-10-05 16:09:15 -07005248 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
5249 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005250 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005251 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005252 return -ENOMEM;
5253 }
5254
Yun Park6c86a662017-10-05 16:09:15 -07005255 QDF_IPA_MSG_META_MSG_TYPE(&meta) = mcc_mode ?
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005256 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Yun Park6c86a662017-10-05 16:09:15 -07005257 hdd_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005258
Yun Park6c86a662017-10-05 16:09:15 -07005259 ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005260
5261 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005262 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Yun Park6c86a662017-10-05 16:09:15 -07005263 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305264 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005265 }
5266
5267 return ret;
5268}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005269
5270/**
5271 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5272 * @mcc_mode: 0=MCC/1=SCC
5273 *
5274 * Return: 0 on success, negative errno value on error
5275 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005276int hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx, bool mcc_mode)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005277{
5278 int ret;
5279
5280 cds_ssr_protect(__func__);
5281 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5282 cds_ssr_unprotect(__func__);
5283
5284 return ret;
5285}
Yun Parka27049a2016-10-11 12:30:49 -07005286#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005287
5288/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005289 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5290 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5291 *
Yun Park6c86a662017-10-05 16:09:15 -07005292 * Return: qdf_ipa_wlan_event representing the hdd_ipa_wlan_event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005293 */
Yun Park6c86a662017-10-05 16:09:15 -07005294static qdf_ipa_wlan_event_t
Mohit Khannafa99aea2016-05-12 21:43:13 -07005295hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5296{
Yun Park6c86a662017-10-05 16:09:15 -07005297 qdf_ipa_wlan_event_t ipa_event;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005298
5299 switch (hdd_ipa_event_type) {
5300 case HDD_IPA_CLIENT_CONNECT:
5301 ipa_event = WLAN_CLIENT_CONNECT;
5302 break;
5303 case HDD_IPA_CLIENT_DISCONNECT:
5304 ipa_event = WLAN_CLIENT_DISCONNECT;
5305 break;
5306 case HDD_IPA_AP_CONNECT:
5307 ipa_event = WLAN_AP_CONNECT;
5308 break;
5309 case HDD_IPA_AP_DISCONNECT:
5310 ipa_event = WLAN_AP_DISCONNECT;
5311 break;
5312 case HDD_IPA_STA_CONNECT:
5313 ipa_event = WLAN_STA_CONNECT;
5314 break;
5315 case HDD_IPA_STA_DISCONNECT:
5316 ipa_event = WLAN_STA_DISCONNECT;
5317 break;
5318 case HDD_IPA_CLIENT_CONNECT_EX:
5319 ipa_event = WLAN_CLIENT_CONNECT_EX;
5320 break;
5321 case HDD_IPA_WLAN_EVENT_MAX:
5322 default:
5323 ipa_event = IPA_WLAN_EVENT_MAX;
5324 break;
5325 }
5326 return ipa_event;
5327
5328}
5329
5330/**
5331 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005332 * @adapter: adapter upon which the event was received
5333 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005334 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005335 * @mac_address: MAC address associated with the event
5336 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005337 * This function is meant to be called from within wlan_hdd_ipa.c
5338 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005339 * Return: 0 on success, negative errno value on error
5340 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005341static int __hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Yun Park6c86a662017-10-05 16:09:15 -07005342 qdf_ipa_wlan_event_t type, uint8_t *mac_addr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005343{
5344 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07005345 qdf_ipa_msg_meta_t meta;
5346 qdf_ipa_wlan_msg_t *msg;
5347 qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005348 int ret;
5349
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005350 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: EVT: %s, MAC: %pM, sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005351 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5352 mac_addr, sta_id);
5353
5354 if (type >= IPA_WLAN_EVENT_MAX)
5355 return -EINVAL;
5356
5357 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5358 return -EINVAL;
5359
5360 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305361 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005362 return -EINVAL;
5363 }
5364
5365 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5366 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005367 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005368 return 0;
5369 }
5370
5371 /*
5372 * During IPA UC resource loading/unloading new events can be issued.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005373 */
Yun Park777d7242017-03-30 15:38:33 -07005374 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5375 (hdd_ipa->resource_loading || hdd_ipa->resource_unloading)) {
5376 unsigned int pending_event_count;
5377 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005378
Yun Park46255682017-10-09 15:56:34 -07005379 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park777d7242017-03-30 15:38:33 -07005380 "%s:IPA resource %s inprogress",
5381 hdd_ipa_wlan_event_to_str(type),
5382 hdd_ipa->resource_loading ?
5383 "load" : "unload");
5384
5385 /* Wait until completion of the long/unloading */
5386 ret = wait_for_completion_timeout(&hdd_ipa->ipa_resource_comp,
5387 msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME));
5388 if (!ret) {
5389 /*
5390 * If timed out, store the events separately and
5391 * handle them later.
5392 */
Yun Park46255682017-10-09 15:56:34 -07005393 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park777d7242017-03-30 15:38:33 -07005394 "IPA resource %s timed out",
5395 hdd_ipa->resource_loading ?
5396 "load" : "unload");
Yun Park7c4f31b2016-11-30 10:09:21 -08005397
Yun Parka4bb37c2017-12-08 16:14:22 -08005398 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005399
Yun Parka4bb37c2017-12-08 16:14:22 -08005400 pending_event_count =
5401 qdf_list_size(&hdd_ipa->pending_event);
5402 if (pending_event_count >=
5403 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
5404 hdd_debug("Reached max pending event count");
5405 qdf_list_remove_front(
5406 &hdd_ipa->pending_event,
5407 (qdf_list_node_t **)&pending_event);
5408 } else {
5409 pending_event =
5410 (struct ipa_uc_pending_event *)
5411 qdf_mem_malloc(sizeof(
Yun Park777d7242017-03-30 15:38:33 -07005412 struct ipa_uc_pending_event));
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005413 }
Yun Parka4bb37c2017-12-08 16:14:22 -08005414
5415 if (!pending_event) {
5416 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5417 "Pending event memory alloc fail");
5418 qdf_mutex_release(&hdd_ipa->ipa_lock);
5419 return -ENOMEM;
5420 }
5421
5422 pending_event->adapter = adapter;
5423 pending_event->sta_id = sta_id;
5424 pending_event->type = type;
5425 pending_event->is_loading =
5426 hdd_ipa->resource_loading;
5427 qdf_mem_copy(pending_event->mac_addr,
5428 mac_addr, QDF_MAC_ADDR_SIZE);
5429 qdf_list_insert_back(&hdd_ipa->pending_event,
5430 &pending_event->node);
5431
5432 qdf_mutex_release(&hdd_ipa->ipa_lock);
5433
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005434 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005435 }
Yun Park46255682017-10-09 15:56:34 -07005436 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Jeff Johnson4929cd92017-10-06 19:21:57 -07005437 "IPA resource %s completed",
5438 hdd_ipa->resource_loading ?
5439 "load" : "unload");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005440 }
5441
5442 hdd_ipa->stats.event[type]++;
5443
Yun Park6c86a662017-10-05 16:09:15 -07005444 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005445 switch (type) {
5446 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005447 qdf_mutex_acquire(&hdd_ipa->event_lock);
5448
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005449 /* STA already connected and without disconnect, connect again
5450 * This is Roaming scenario
5451 */
5452 if (hdd_ipa->sta_connected)
5453 hdd_ipa_cleanup_iface(adapter->ipa_context);
5454
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005455 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5456 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305457 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005458 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005459 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005460
Yun Park8f289c82016-10-18 16:38:21 -07005461 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5462 (hdd_ipa->sap_num_connected_sta > 0) &&
5463 !hdd_ipa->sta_connected) {
5464 qdf_mutex_release(&hdd_ipa->event_lock);
5465 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005466 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005467 qdf_mutex_acquire(&hdd_ipa->event_lock);
5468 }
5469
Jeff Johnson1b780e42017-10-31 14:11:45 -07005470 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005471 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005472 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005473
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005474 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005475
5476 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005477
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005478 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005479 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005480 break;
5481
5482 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005483 qdf_mutex_acquire(&hdd_ipa->event_lock);
5484
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005485 /* For DFS channel we get two start_bss event (before and after
5486 * CAC). Also when ACS range includes both DFS and non DFS
5487 * channels, we could possibly change channel many times due to
5488 * RADAR detection and chosen channel may not be a DFS channels.
5489 * So dont return error here. Just discard the event.
5490 */
Yun Park8f289c82016-10-18 16:38:21 -07005491 if (adapter->ipa_context) {
5492 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005493 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005494 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005495
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005496 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5497 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005498 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005499 hdd_err("%s: Evt: %d, Interface setup failed",
Yun Park6c86a662017-10-05 16:09:15 -07005500 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005501 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005502 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005503
Yun Park8f289c82016-10-18 16:38:21 -07005504 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5505 qdf_mutex_release(&hdd_ipa->event_lock);
5506 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005507 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005508 qdf_mutex_acquire(&hdd_ipa->event_lock);
5509 }
5510
Jeff Johnson1b780e42017-10-31 14:11:45 -07005511 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005512 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005513 (adapter->ipa_context))->iface_id;
5514
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305515 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005516 break;
5517
5518 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305519 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005520
5521 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005522 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005523 hdd_err("%s: Evt: %d, STA already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005524 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005525 return -EINVAL;
5526 }
Yun Parka37592b2016-06-11 17:10:28 -07005527
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005528 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005529
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005530 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005531 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005532 msg_ex->name);
5533 } else {
5534 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Park3b7152b2017-08-25 08:33:37 -07005535 if ((1 == hdd_ipa->num_iface) &&
Yun Parka37592b2016-06-11 17:10:28 -07005536 (HDD_IPA_UC_NUM_WDI_PIPE ==
Yun Park3b7152b2017-08-25 08:33:37 -07005537 hdd_ipa->activated_fw_pipe) &&
5538 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005539 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005540 }
5541
Yun Park74127cf2016-09-18 11:22:41 -07005542 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5543 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005544 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005545 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005546 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005547 qdf_mutex_acquire(&hdd_ipa->event_lock);
Jeff Johnson1b780e42017-10-31 14:11:45 -07005548 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005549 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005550 }
5551
Yun Park8f289c82016-10-18 16:38:21 -07005552 hdd_ipa_cleanup_iface(adapter->ipa_context);
5553
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305554 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005555
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005556 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005557 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005558 break;
5559
5560 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005561 qdf_mutex_acquire(&hdd_ipa->event_lock);
5562
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005563 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005564 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005565 hdd_err("%s: Evt: %d, SAP already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005566 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005567 return -EINVAL;
5568 }
5569
Yun Park3b7152b2017-08-25 08:33:37 -07005570 if ((1 == hdd_ipa->num_iface) &&
5571 (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
5572 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005573 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005574 /*
5575 * We disable WDI pipes directly here since
5576 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5577 * processed when unloading WLAN driver is in
5578 * progress
5579 */
5580 hdd_ipa_uc_disable_pipes(hdd_ipa);
5581 } else {
Yun Park199c2ed2017-10-02 11:24:22 -07005582 /*
5583 * This shouldn't happen :
5584 * No interface left but WDI pipes are still
5585 * active - force close WDI pipes
5586 */
5587 WARN_ON(1);
5588 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
5589 "No interface left but WDI pipes are still active - force close WDI pipes");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005590 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5591 }
5592 }
5593
5594 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005595 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005596 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005597 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005598 qdf_mutex_acquire(&hdd_ipa->event_lock);
Jeff Johnson1b780e42017-10-31 14:11:45 -07005599 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005600 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005601 }
Yun Parka37592b2016-06-11 17:10:28 -07005602
Yun Park8f289c82016-10-18 16:38:21 -07005603 hdd_ipa_cleanup_iface(adapter->ipa_context);
5604
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305605 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005606 break;
5607
5608 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005609 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005610 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005611 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305612 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005613 return 0;
5614 }
5615
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305616 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005617 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5618 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005619 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305620 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005621 "%s: STA ID %d found, not valid",
5622 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005623 return 0;
5624 }
Yun Park312f71a2015-12-08 10:22:42 -08005625
5626 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005627 if (hdd_ipa->sap_num_connected_sta == 0 &&
5628 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005629 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005630 hdd_ipa->sta_connected) {
5631 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005632 hdd_ipa_uc_offload_enable_disable(
5633 hdd_get_adapter(hdd_ipa->hdd_ctx,
5634 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005635 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005636 qdf_mutex_acquire(&hdd_ipa->event_lock);
5637 }
Yun Parka37592b2016-06-11 17:10:28 -07005638
Yun Park312f71a2015-12-08 10:22:42 -08005639 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5640 if (ret) {
Yun Park46255682017-10-09 15:56:34 -07005641 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park312f71a2015-12-08 10:22:42 -08005642 "%s: handle 1st con ret %d",
5643 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005644
5645 if (hdd_ipa_uc_sta_is_enabled(
5646 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005647 hdd_ipa->sta_connected) {
5648 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005649 hdd_ipa_uc_offload_enable_disable(
5650 hdd_get_adapter(
5651 hdd_ipa->hdd_ctx,
5652 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005653 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005654 } else {
5655 qdf_mutex_release(&hdd_ipa->event_lock);
5656 }
Yun Parka37592b2016-06-11 17:10:28 -07005657
Yun Park312f71a2015-12-08 10:22:42 -08005658 return ret;
5659 }
5660 }
5661
5662 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005663
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305664 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005665
Yun Park6c86a662017-10-05 16:09:15 -07005666 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
5667 QDF_IPA_MSG_META_MSG_LEN(&meta) =
5668 (sizeof(qdf_ipa_wlan_msg_ex_t) +
5669 sizeof(qdf_ipa_wlan_hdr_attrib_val_t));
5670 msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005671
5672 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305673 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005674 "msg_ex allocation failed");
5675 return -ENOMEM;
5676 }
5677 strlcpy(msg_ex->name, adapter->dev->name,
5678 IPA_RESOURCE_NAME_MAX);
5679 msg_ex->num_of_attribs = 1;
5680 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5681 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5682 msg_ex->attribs[0].offset =
5683 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5684 } else {
5685 msg_ex->attribs[0].offset =
5686 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5687 }
5688 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5689 IPA_MAC_ADDR_SIZE);
5690
5691 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5692
5693 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005694 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305695 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305696 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005697 return ret;
5698 }
5699 hdd_ipa->stats.num_send_msg++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005700
Yun Park199c2ed2017-10-02 11:24:22 -07005701 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005702 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005703 return ret;
5704
5705 case WLAN_CLIENT_DISCONNECT:
5706 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005707 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005708 "%s: IPA UC OFFLOAD NOT ENABLED",
5709 msg_ex->name);
5710 return 0;
5711 }
5712
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305713 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Park73ea8bb2017-08-25 07:27:39 -07005714 if (!hdd_ipa->sap_num_connected_sta) {
5715 qdf_mutex_release(&hdd_ipa->event_lock);
5716 hdd_err("%s: Evt: %d, Client already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005717 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Yun Park73ea8bb2017-08-25 07:27:39 -07005718 return 0;
5719 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005720 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005721 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305722 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005723 "%s: STA ID %d NOT found, not valid",
5724 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005725 return 0;
5726 }
5727 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005728
Yun Park9b5030f2016-11-08 12:02:37 -08005729 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005730 if (!hdd_ipa->sap_num_connected_sta &&
5731 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005732 if ((false == hdd_ipa->resource_unloading)
5733 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305734 hdd_ipa->activated_fw_pipe) &&
5735 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005736 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5737 }
5738
Yun Park9b5030f2016-11-08 12:02:37 -08005739 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jiad9d472c92017-07-28 14:05:31 +08005740 hdd_ipa->sta_connected) {
5741 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005742 hdd_ipa_uc_offload_enable_disable(
5743 hdd_get_adapter(hdd_ipa->hdd_ctx,
5744 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005745 SIR_STA_RX_DATA_OFFLOAD, false);
jiad9d472c92017-07-28 14:05:31 +08005746 } else {
5747 qdf_mutex_release(&hdd_ipa->event_lock);
5748 }
Yun Park8f289c82016-10-18 16:38:21 -07005749 } else {
5750 qdf_mutex_release(&hdd_ipa->event_lock);
5751 }
Yun Parkfec73dc2017-09-06 10:40:07 -07005752
Yun Park199c2ed2017-10-02 11:24:22 -07005753 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005754 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005755 break;
5756
5757 default:
5758 return 0;
5759 }
5760
Yun Park6c86a662017-10-05 16:09:15 -07005761 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
5762 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005763 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305764 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005765 return -ENOMEM;
5766 }
5767
Yun Park6c86a662017-10-05 16:09:15 -07005768 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
5769 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), adapter->dev->name,
5770 IPA_RESOURCE_NAME_MAX);
5771 memcpy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, ETH_ALEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005772
Srinivas Girigowda97852372017-03-06 16:52:59 -08005773 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Yun Park6c86a662017-10-05 16:09:15 -07005774 QDF_IPA_WLAN_MSG_NAME(msg),
5775 QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005776
5777 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5778
5779 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005780 hdd_err("%s: Evt: %d fail:%d",
Yun Park6c86a662017-10-05 16:09:15 -07005781 QDF_IPA_WLAN_MSG_NAME(msg),
5782 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305783 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005784 return ret;
5785 }
5786
5787 hdd_ipa->stats.num_send_msg++;
5788
5789end:
5790 return ret;
5791}
5792
5793/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005794 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005795 * @adapter: adapter upon which the event was received
5796 * @sta_id: station id for the event
5797 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5798 * @mac_address: MAC address associated with the event
5799 *
5800 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5801 *
5802 * Return: 0 on success, negative errno value on error
5803 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005804int hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005805 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5806{
Yun Park6c86a662017-10-05 16:09:15 -07005807 qdf_ipa_wlan_event_t type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005808 int ret = 0;
5809
5810 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005811
Leo Changa202b522016-10-14 16:13:50 -07005812 /* Data path offload only support for STA and SAP mode */
5813 if ((QDF_STA_MODE == adapter->device_mode) ||
5814 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005815 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005816
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005817 cds_ssr_unprotect(__func__);
5818
5819 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005820}
5821
5822/**
5823 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5824 * @hdd_ipa: Global HDD IPA context
Yun Parka4bb37c2017-12-08 16:14:22 -08005825 * @is_loading: Indicate if invoked during loading
Mohit Khannafa99aea2016-05-12 21:43:13 -07005826 *
5827 * Return: None
5828 */
5829static void
Yun Parka4bb37c2017-12-08 16:14:22 -08005830hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa, bool is_loading)
Mohit Khannafa99aea2016-05-12 21:43:13 -07005831{
5832 unsigned int pending_event_count;
5833 struct ipa_uc_pending_event *pending_event = NULL;
5834
5835 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005836 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07005837 "Pending Event Count %d", pending_event_count);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005838 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005839 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07005840 "No Pending Event");
Mohit Khannafa99aea2016-05-12 21:43:13 -07005841 return;
5842 }
5843
5844 qdf_list_remove_front(&hdd_ipa->pending_event,
5845 (qdf_list_node_t **)&pending_event);
5846 while (pending_event != NULL) {
Yun Parka4bb37c2017-12-08 16:14:22 -08005847 if (pending_event->is_loading == is_loading)
5848 __hdd_ipa_wlan_evt(pending_event->adapter,
5849 pending_event->sta_id,
5850 pending_event->type,
5851 pending_event->mac_addr);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005852 qdf_mem_free(pending_event);
5853 pending_event = NULL;
5854 qdf_list_remove_front(&hdd_ipa->pending_event,
5855 (qdf_list_node_t **)&pending_event);
5856 }
5857}
5858
5859/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005860 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5861 * @state: IPA RM state value
5862 *
5863 * Return: ASCII string representing the IPA RM state
5864 */
5865static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5866{
5867 switch (state) {
5868 case HDD_IPA_RM_RELEASED:
5869 return "RELEASED";
5870 case HDD_IPA_RM_GRANT_PENDING:
5871 return "GRANT_PENDING";
5872 case HDD_IPA_RM_GRANTED:
5873 return "GRANTED";
5874 }
5875
5876 return "UNKNOWN";
5877}
5878
5879/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005880 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005881 * @hdd_ctx: HDD global context
5882 *
5883 * Allocate hdd_ipa resources, ipa pipe resource and register
5884 * wlan interface with IPA module.
5885 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305886 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005887 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005888static QDF_STATUS __hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005889{
5890 struct hdd_ipa_priv *hdd_ipa = NULL;
5891 int ret, i;
5892 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005893 struct ol_txrx_pdev_t *pdev = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07005894 qdf_ipa_rm_perf_profile_t profile;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005895
5896 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305897 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005898
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08005899 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Park199c2ed2017-10-02 11:24:22 -07005900
Yun Parkbaa62862017-01-18 13:43:34 -08005901 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005902 if (!pdev) {
5903 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5904 goto fail_return;
5905 }
5906
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305907 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005908 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305909 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005910 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005911 }
5912
5913 hdd_ctx->hdd_ipa = hdd_ipa;
5914 ghdd_ipa = hdd_ipa;
5915 hdd_ipa->hdd_ctx = hdd_ctx;
5916 hdd_ipa->num_iface = 0;
5917
5918 /* Create the interface context */
5919 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5920 iface_context = &hdd_ipa->iface_context[i];
5921 iface_context->hdd_ipa = hdd_ipa;
5922 iface_context->cons_client =
5923 hdd_ipa_adapter_2_client[i].cons_client;
5924 iface_context->prod_client =
5925 hdd_ipa_adapter_2_client[i].prod_client;
5926 iface_context->iface_id = i;
5927 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305928 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005929 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005930
Leo Chang69c39692016-10-12 20:11:12 -07005931 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305932 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07005933 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305934 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005935 qdf_list_create(&hdd_ipa->pending_event, 1000);
5936 qdf_mutex_create(&hdd_ipa->event_lock);
5937 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005938
5939 ret = hdd_ipa_setup_rm(hdd_ipa);
5940 if (ret)
5941 goto fail_setup_rm;
5942
Yun Park9281cb72017-11-30 11:14:30 -08005943 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++)
5944 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
5945 sizeof(struct hdd_ipa_sys_pipe));
5946
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005947 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5948 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305949 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005950 hdd_ipa->sap_num_connected_sta = 0;
5951 hdd_ipa->ipa_tx_packets_diff = 0;
5952 hdd_ipa->ipa_rx_packets_diff = 0;
5953 hdd_ipa->ipa_p_tx_packets = 0;
5954 hdd_ipa->ipa_p_rx_packets = 0;
5955 hdd_ipa->resource_loading = false;
5956 hdd_ipa->resource_unloading = false;
5957 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005958 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08005959 hdd_ipa->wdi_enabled = false;
Yun Park9281cb72017-11-30 11:14:30 -08005960 /* Setup IPA system pipes */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005961 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5962 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5963 if (ret)
5964 goto fail_create_sys_pipe;
5965 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005966 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5967 goto fail_create_sys_pipe;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005968 } else {
5969 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5970 if (ret)
5971 goto fail_create_sys_pipe;
5972 }
5973
Yun Park66f24c42017-03-20 10:39:47 -07005974 /* When IPA clock scaling is disabled, initialze maximum clock */
5975 if (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)) {
5976 profile.max_supported_bandwidth_mbps = 800;
5977 hdd_debug("IPA clock scaling is disabled.");
5978 hdd_debug("Set initial CONS/PROD perf: %d",
5979 profile.max_supported_bandwidth_mbps);
5980 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
5981 &profile);
5982 if (ret) {
5983 hdd_err("RM CONS set perf profile failed: %d", ret);
5984 goto fail_create_sys_pipe;
5985 }
5986
5987 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
5988 &profile);
5989 if (ret) {
5990 hdd_err("RM PROD set perf profile failed: %d", ret);
5991 goto fail_create_sys_pipe;
5992 }
5993 }
5994
Yun Park777d7242017-03-30 15:38:33 -07005995 init_completion(&hdd_ipa->ipa_resource_comp);
5996
Yun Parke4239802018-01-09 11:01:40 -08005997 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305998 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005999
6000fail_create_sys_pipe:
6001 hdd_ipa_destroy_rm_resource(hdd_ipa);
6002fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306003 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306004 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08006005 hdd_ctx->hdd_ipa = NULL;
6006 ghdd_ipa = NULL;
6007fail_return:
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08006008 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: fail");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306009 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006010}
6011
6012/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006013 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
6014 * @hdd_ctx: HDD global context
6015 *
6016 * Allocate hdd_ipa resources, ipa pipe resource and register
6017 * wlan interface with IPA module.
6018 *
6019 * Return: QDF_STATUS enumeration
6020 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07006021QDF_STATUS hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006022{
6023 QDF_STATUS ret;
6024
6025 cds_ssr_protect(__func__);
6026 ret = __hdd_ipa_init(hdd_ctx);
6027 cds_ssr_unprotect(__func__);
6028
6029 return ret;
6030}
6031
Arun Khandavallicc544b32017-01-30 19:52:16 +05306032
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006033/**
Govind Singh1dab23b2017-08-12 13:31:00 +05306034 * __hdd_ipa_flush - flush IPA exception path SKB's
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006035 * @hdd_ctx: HDD global context
6036 *
Govind Singh1dab23b2017-08-12 13:31:00 +05306037 * Return: none
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006038 */
Govind Singh1dab23b2017-08-12 13:31:00 +05306039static void __hdd_ipa_flush(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006040{
6041 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
Nirav Shahcbc6d722016-03-01 16:24:53 +05306042 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006043 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
6044
6045 if (!hdd_ipa_is_enabled(hdd_ctx))
Govind Singh1dab23b2017-08-12 13:31:00 +05306046 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006047
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006048 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006049
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306050 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006051
Nirav Shahcbc6d722016-03-01 16:24:53 +05306052 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
6053 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306054 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006055
6056 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07006057 if (pm_tx_cb->ipa_tx_desc)
6058 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006059
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306060 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006061 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306062 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Govind Singh1dab23b2017-08-12 13:31:00 +05306063}
6064
6065/**
6066 * __hdd_ipa_cleanup - IPA cleanup function
6067 * @hdd_ctx: HDD global context
6068 *
6069 * Return: QDF_STATUS enumeration
6070 */
6071static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
6072{
6073 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
6074 int i;
6075 struct hdd_ipa_iface_context *iface_context = NULL;
6076
6077 if (!hdd_ipa_is_enabled(hdd_ctx))
6078 return QDF_STATUS_SUCCESS;
6079
6080 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
6081 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
6082 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6083 }
6084
6085 /* Teardown IPA sys_pipe for MCC */
6086 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
6087 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6088
6089 hdd_ipa_destroy_rm_resource(hdd_ipa);
6090
6091 __hdd_ipa_flush(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306093 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006094 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006095
6096 /* destory the interface lock */
6097 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6098 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306099 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006100 }
6101
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006102 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08006103 if (ipa_uc_dereg_rdyCB())
6104 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
6105 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006106 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306107 qdf_mutex_destroy(&hdd_ipa->event_lock);
6108 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07006109 qdf_list_destroy(&hdd_ipa->pending_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006110
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006111 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6112 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
Yun Park6edb2172018-01-14 00:18:05 -08006113 qdf_mem_free(hdd_ipa->uc_op_work[i].msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006114 hdd_ipa->uc_op_work[i].msg = NULL;
6115 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006116 }
6117
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306118 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006119 hdd_ctx->hdd_ipa = NULL;
6120
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306121 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006122}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006123
6124/**
Govind Singh1dab23b2017-08-12 13:31:00 +05306125 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_flush
6126 * @hdd_ctx: HDD global context
6127 *
6128 * Return: None
6129 */
6130void hdd_ipa_flush(struct hdd_context *hdd_ctx)
6131{
6132 cds_ssr_protect(__func__);
6133 __hdd_ipa_flush(hdd_ctx);
6134 cds_ssr_unprotect(__func__);
6135}
6136
6137/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006138 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
6139 * @hdd_ctx: HDD global context
6140 *
6141 * Return: QDF_STATUS enumeration
6142 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07006143QDF_STATUS hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006144{
6145 QDF_STATUS ret;
6146
6147 cds_ssr_protect(__func__);
6148 ret = __hdd_ipa_cleanup(hdd_ctx);
6149 cds_ssr_unprotect(__func__);
6150
6151 return ret;
6152}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006153#endif /* IPA_OFFLOAD */