blob: 6c9b8a1a0eb7a461049c48e1d9d9c2e574f6d705 [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
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700508#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)
Leo Chang63d73612016-10-18 18:09:43 -0700509#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800510#else
511/* Do nothing */
Leo Chang63d73612016-10-18 18:09:43 -0700512#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700513#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800514
Yun Park0dad1002017-07-14 14:57:01 -0700515#define HDD_IPA_DBG_DUMP_RX_LEN 84
Yun Parkb187d542016-11-14 18:10:04 -0800516#define HDD_IPA_DBG_DUMP_TX_LEN 48
517
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800518static struct hdd_ipa_adapter_2_client {
Yun Park6c86a662017-10-05 16:09:15 -0700519 qdf_ipa_client_type_t cons_client;
520 qdf_ipa_client_type_t prod_client;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800521} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
522 {
523 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
524 }, {
525 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
526 }, {
527 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
528 },
529};
530
Yun Park637d6482016-10-05 10:51:33 -0700531#ifdef FEATURE_METERING
532#define IPA_UC_SHARING_STATES_WAIT_TIME 500
533#define IPA_UC_SET_QUOTA_WAIT_TIME 500
534#endif
535
Yun Park777d7242017-03-30 15:38:33 -0700536#define IPA_RESOURCE_COMP_WAIT_TIME 100
537
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800538static struct hdd_ipa_priv *ghdd_ipa;
539
540/* Local Function Prototypes */
Yun Park6c86a662017-10-05 16:09:15 -0700541static void hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800542 unsigned long data);
Yun Park6c86a662017-10-05 16:09:15 -0700543static void hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800544 unsigned long data);
Yun Parkb4f591d2017-03-29 15:51:01 -0700545#ifdef FEATURE_METERING
Yun Park6c86a662017-10-05 16:09:15 -0700546static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Parkb4f591d2017-03-29 15:51:01 -0700547 void *data);
548#else
549static void hdd_ipa_wdi_meter_notifier_cb(void);
550#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800551static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800552
553static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Yun Parka4bb37c2017-12-08 16:14:22 -0800554static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa,
555 bool is_loading);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800556
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800557#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
558 defined(IPA_CLIENT_IS_MHI_CONS))
559/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800560 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
561 * @priv_ctxt: hdd ipa local context
562 *
563 * Will be called by IPA context.
564 * It's atomic context, then should be scheduled to kworker thread
565 *
566 * Return: None
567 */
568static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
569{
570 struct hdd_ipa_priv *hdd_ipa;
571 struct op_msg_type *msg;
572 struct uc_op_work_struct *uc_op_work;
573
574 if (priv_ctxt == NULL) {
575 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
576 return;
577 }
578
579 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
Yun Park6edb2172018-01-14 00:18:05 -0800580 hdd_ipa->uc_loaded = true;
581
582 uc_op_work = &hdd_ipa->uc_op_work[HDD_IPA_UC_OPCODE_UC_READY];
583
584 if (!list_empty(&uc_op_work->work.entry))
585 /* uc_op_work is not initialized yet */
586 return;
587
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800588 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
589 if (!msg) {
590 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
591 return;
592 }
593
594 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
595
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800596 /* When the same uC OPCODE is already pended, just return */
597 if (uc_op_work->msg)
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530598 goto done;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800599
600 uc_op_work->msg = msg;
601 schedule_work(&uc_op_work->work);
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530602
jiadd91a6842017-08-01 14:46:02 +0800603 /* work handler will free the msg buffer */
604 return;
605
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530606done:
607 qdf_mem_free(msg);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800608}
609
610/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800611 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
612 * @ctrl: WDI control value
613 *
614 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
615 *
616 * Return: 0 on message send to ipa, -1 on failure
617 */
618static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
619{
Yun Park6c86a662017-10-05 16:09:15 -0700620 qdf_ipa_msg_meta_t meta;
621 qdf_ipa_wlan_msg_t *ipa_msg;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800622 int ret = 0;
623
624 /* WDI enable message to IPA */
Yun Park6c86a662017-10-05 16:09:15 -0700625 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg);
626 ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800627 if (ipa_msg == NULL) {
628 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
629 "msg allocation failed");
630 return -ENOMEM;
631 }
632
633 if (ctrl == true)
Yun Park6c86a662017-10-05 16:09:15 -0700634 QDF_IPA_MSG_META_MSG_TYPE(&meta) = WLAN_WDI_ENABLE;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800635 else
Yun Park6c86a662017-10-05 16:09:15 -0700636 QDF_IPA_MSG_META_MSG_TYPE(&meta) = WLAN_WDI_DISABLE;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800637
Srinivas Girigowda97852372017-03-06 16:52:59 -0800638 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park6c86a662017-10-05 16:09:15 -0700639 "ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
640 ret = qdf_ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800641 if (ret) {
642 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
643 "ipa_send_msg(Evt:%d)-fail=%d",
Yun Park6c86a662017-10-05 16:09:15 -0700644 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800645 qdf_mem_free(ipa_msg);
646 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800647 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800648}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800649
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800650/**
651 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
652 * @hdd_ipa: HDD IPA local context
653 *
654 * Register IPA UC ready callback function to IPA kernel driver
655 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
656 * open WDI pipe after WLAN driver loading finished
657 *
658 * Return: 0 Success
659 * -EPERM Registration fail
660 */
661static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
662{
Yun Park6c86a662017-10-05 16:09:15 -0700663 qdf_ipa_wdi_uc_ready_params_t uc_ready_param;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800664 int ret = 0;
665
666 hdd_ipa->uc_loaded = false;
Yun Park6c86a662017-10-05 16:09:15 -0700667 QDF_IPA_UC_READY_PARAMS_PRIV(&uc_ready_param) = (void *)hdd_ipa;
668 QDF_IPA_UC_READY_PARAMS_NOTIFY(&uc_ready_param) =
669 hdd_ipa_uc_loaded_uc_cb;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800670 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
671 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
672 "UC Ready CB register fail");
673 return -EPERM;
674 }
Yun Park6c86a662017-10-05 16:09:15 -0700675 if (false != QDF_IPA_UC_READY_PARAMS_IS_UC_READY(&uc_ready_param)) {
Srinivas Girigowda2b5d47c2017-03-29 00:28:46 -0700676 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800677 hdd_ipa->uc_loaded = true;
678 } else {
679 ret = hdd_ipa_uc_send_wdi_control_msg(false);
680 }
681
682 return ret;
683}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800684#else
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800685static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
686{
687 hdd_ipa->uc_loaded = true;
688 return 0;
689}
690
691static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
692{
693 return 0;
694}
695#endif
696
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800697/**
698 * hdd_ipa_is_enabled() - Is IPA enabled?
699 * @hdd_ctx: Global HDD context
700 *
701 * Return: true if IPA is enabled, false otherwise
702 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700703bool hdd_ipa_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800704{
705 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
706}
707
708/**
709 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
710 * @hdd_ctx: Global HDD context
711 *
712 * Return: true if IPA uC offload is enabled, false otherwise
713 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700714bool hdd_ipa_uc_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800715{
716 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
717}
718
719/**
720 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
721 * @hdd_ctx: Global HDD context
722 *
723 * Return: true if STA mode IPA uC offload is enabled, false otherwise
724 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700725static inline bool hdd_ipa_uc_sta_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800726{
727 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
728}
729
730/**
Guolei Bianca144d82016-11-10 11:07:42 +0800731 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
732 * @hdd_ipa: Global HDD IPA context
733 *
734 * Return: None
735 */
Guolei Bianca144d82016-11-10 11:07:42 +0800736static inline void hdd_ipa_uc_sta_reset_sta_connected(
737 struct hdd_ipa_priv *hdd_ipa)
738{
Yun Park637d6482016-10-05 10:51:33 -0700739 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800740 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700741 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800742}
Guolei Bianca144d82016-11-10 11:07:42 +0800743
744/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
746 * @hdd_ipa: Global HDD IPA context
747 *
748 * Return: true if pre-filter is enabled, otherwise false
749 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700750static inline bool hdd_ipa_is_pre_filter_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800751{
752 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
753 HDD_IPA_PRE_FILTER_ENABLE_MASK);
754}
755
756/**
757 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
758 * @hdd_ipa: Global HDD IPA context
759 *
760 * Return: true if IPv6 is enabled, otherwise false
761 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700762static inline bool hdd_ipa_is_ipv6_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800763{
764 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
765}
766
767/**
768 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
769 * @hdd_ipa: Global HDD IPA context
770 *
771 * Return: true if resource manager is enabled, otherwise false
772 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700773static inline bool hdd_ipa_is_rm_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800774{
775 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
776}
777
778/**
779 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
780 * @hdd_ipa: Global HDD IPA context
781 *
782 * Return: true if resource manager is enabled, otherwise false
783 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700784static inline bool hdd_ipa_is_rt_debugging_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800785{
786 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
787}
788
789/**
790 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
791 * @hdd_ipa: Global HDD IPA context
792 *
793 * Return: true if clock scaling is enabled, otherwise false
794 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700795static inline bool hdd_ipa_is_clk_scaling_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796{
797 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
798 HDD_IPA_CLK_SCALING_ENABLE_MASK |
799 HDD_IPA_RM_ENABLE_MASK);
800}
801
802/**
803 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
804 * @ctext: pointer to hdd context.
805 *
806 * If rt debug enabled, periodically called, and fill debug buffer
807 *
808 * Return: none
809 */
810static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
811{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700812 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813 struct hdd_ipa_priv *hdd_ipa;
814 struct uc_rt_debug_info *dump_info = NULL;
815
816 if (wlan_hdd_validate_context(hdd_ctx))
817 return;
818
819 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700820 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800821 return;
822 }
823
824 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
825
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530826 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800827 dump_info = &hdd_ipa->rt_bug_buffer[
828 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
829
Deepthi Gowri6acee342016-10-28 15:00:38 +0530830 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800831 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
Yun Park46255682017-10-09 15:56:34 -0700832 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internal_drop_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800835 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
836 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800837 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
838 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530839 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840
Anurag Chouhan210db072016-02-22 18:42:15 +0530841 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800842 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
843}
844
845/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700846 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847 * @hdd_ctx: pointer to hdd context.
848 *
849 * If rt debug enabled, dump debug buffer contents based on requirement
850 *
851 * Return: none
852 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700853static void __hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854{
855 struct hdd_ipa_priv *hdd_ipa;
856 unsigned int dump_count;
857 unsigned int dump_index;
858 struct uc_rt_debug_info *dump_info = NULL;
859
860 if (wlan_hdd_validate_context(hdd_ctx))
861 return;
862
863 hdd_ipa = hdd_ctx->hdd_ipa;
864 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700865 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 return;
867 }
868
Chris Guo1751acf2017-07-03 14:09:01 +0800869 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
870 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -0700871 "IPA RT debug is not enabled");
Chris Guo1751acf2017-07-03 14:09:01 +0800872 return;
873 }
874
Yun Park46255682017-10-09 15:56:34 -0700875 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800876 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Yun Park46255682017-10-09 15:56:34 -0700877 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Parkb187d542016-11-14 18:10:04 -0800878 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800879
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530880 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800881 for (dump_count = 0;
882 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
883 dump_count++) {
884 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
885 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
886 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Yun Park46255682017-10-09 15:56:34 -0700887 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530888 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800889 dump_info->time, dump_info->ipa_excep_count,
890 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800891 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800892 dump_info->rx_destructor_call,
893 dump_info->rx_discard_count);
894 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530895 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Yun Park46255682017-10-09 15:56:34 -0700896 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800897 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
898}
899
900/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700901 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
902 * __hdd_ipa_uc_rt_debug_host_dump
903 * @hdd_ctx: pointer to hdd context.
904 *
905 * If rt debug enabled, dump debug buffer contents based on requirement
906 *
907 * Return: none
908 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700909void hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700910{
911 cds_ssr_protect(__func__);
912 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
913 cds_ssr_unprotect(__func__);
914}
915
916/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
918 * @ctext: pointer to hdd context.
919 *
920 * periodically called by timer expire
921 * will try to alloc dummy memory and detect out of memory condition
922 * if out of memory detected, dump wlan-ipa stats
923 *
924 * Return: none
925 */
926static void hdd_ipa_uc_rt_debug_handler(void *ctext)
927{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700928 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700929 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800930 void *dummy_ptr = NULL;
931
932 if (wlan_hdd_validate_context(hdd_ctx))
933 return;
934
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700935 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
936
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800937 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700938 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
939 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800940 return;
941 }
942
943 /* Allocate dummy buffer periodically and free immediately. this will
944 * proactively detect OOM and if allocation fails dump ipa stats
945 */
946 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
947 GFP_KERNEL | GFP_ATOMIC);
948 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
950 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -0700951 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
952 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800953 } else {
954 kfree(dummy_ptr);
955 }
956
Anurag Chouhan210db072016-02-22 18:42:15 +0530957 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800958 HDD_IPA_UC_RT_DEBUG_PERIOD);
959}
960
961/**
Yun Parkb187d542016-11-14 18:10:04 -0800962 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800963 * @skb: packet pinter
964 *
965 * when free data packet, will be invoked by wlan client and will increase
966 * free counter
967 *
968 * Return: none
969 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700970static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800971{
972 if (!ghdd_ipa) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700973 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "invalid hdd context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800974 return;
975 }
976
977 ghdd_ipa->ipa_rx_destructor_count++;
978}
979
980/**
Yun Parkb187d542016-11-14 18:10:04 -0800981 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800982 * @hdd_ctx: hdd main context
983 *
984 * free all rt debugging resources
985 *
986 * Return: none
987 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700988static void hdd_ipa_uc_rt_debug_deinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700990 struct hdd_ipa_priv *hdd_ipa;
991
992 if (wlan_hdd_validate_context(hdd_ctx))
993 return;
994
995 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800996
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530997 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800998
999 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001000 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1001 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001002 return;
1003 }
1004
Anurag Chouhan210db072016-02-22 18:42:15 +05301005 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -08001006 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
1007 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1008 }
1009 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1010
1011 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301012 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1013 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301015 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001016}
1017
1018/**
Yun Parkb187d542016-11-14 18:10:04 -08001019 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001020 * @hdd_ctx: hdd main context
1021 *
1022 * alloc and initialize all rt debugging resources
1023 *
1024 * Return: none
1025 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001026static void hdd_ipa_uc_rt_debug_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001028 struct hdd_ipa_priv *hdd_ipa;
1029
Chris Guo1751acf2017-07-03 14:09:01 +08001030 if (wlan_hdd_validate_context_in_loading(hdd_ctx))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001031 return;
1032
1033 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301035 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001036 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301037 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001038 sizeof(struct uc_rt_debug_info) *
1039 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1040 hdd_ipa->ipa_tx_forward = 0;
1041 hdd_ipa->ipa_rx_discard = 0;
1042 hdd_ipa->ipa_rx_net_send_count = 0;
Yun Park46255682017-10-09 15:56:34 -07001043 hdd_ipa->ipa_rx_internal_drop_count = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044 hdd_ipa->ipa_rx_destructor_count = 0;
1045
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046 /* Reatime debug enable on feature enable */
1047 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001048 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1049 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001050 return;
1051 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001052
1053 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1054 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1055 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1056 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1057
Anurag Chouhan210db072016-02-22 18:42:15 +05301058 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001059 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301060 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001061 HDD_IPA_UC_RT_DEBUG_PERIOD);
1062
1063}
1064
1065/**
Yun Parkb187d542016-11-14 18:10:04 -08001066 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1067 * @hdd_ipa: HDD IPA struct
1068 *
1069 * Dump entries in struct hdd_ipa
1070 *
1071 * Return: none
1072 */
1073static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1074{
1075 int i;
1076
1077 /* HDD IPA */
Yun Park46255682017-10-09 15:56:34 -07001078 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1079 "\n==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001080 "num_iface: %d\n"
1081 "rm_state: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001082 "rm_lock: %pK\n"
1083 "uc_rm_work: %pK\n"
1084 "uc_op_work: %pK\n"
1085 "wake_lock: %pK\n"
1086 "wake_lock_work: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001087 "wake_lock_released: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001088 "tx_ref_cnt: %d\n"
1089 "pm_queue_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001090 "\thead: %pK\n"
1091 "\ttail: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001092 "\tqlen: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001093 "pm_work: %pK\n"
1094 "pm_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001095 "suspended: %d\n",
1096 hdd_ipa->num_iface,
1097 hdd_ipa->rm_state,
1098 &hdd_ipa->rm_lock,
1099 &hdd_ipa->uc_rm_work,
1100 &hdd_ipa->uc_op_work,
1101 &hdd_ipa->wake_lock,
1102 &hdd_ipa->wake_lock_work,
1103 hdd_ipa->wake_lock_released,
Yun Parkb187d542016-11-14 18:10:04 -08001104 hdd_ipa->tx_ref_cnt.counter,
1105 hdd_ipa->pm_queue_head.head,
1106 hdd_ipa->pm_queue_head.tail,
1107 hdd_ipa->pm_queue_head.qlen,
1108 &hdd_ipa->pm_work,
1109 &hdd_ipa->pm_lock,
1110 hdd_ipa->suspended);
Yun Park46255682017-10-09 15:56:34 -07001111
1112 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1113 "\nq_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001114 "pend_desc_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001115 "\tnext: %pK\n"
1116 "\tprev: %pK\n"
1117 "hdd_ctx: %pK\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001118 "stats: %pK\n"
1119 "ipv4_notifier: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001120 "curr_prod_bw: %d\n"
1121 "curr_cons_bw: %d\n"
1122 "activated_fw_pipe: %d\n"
1123 "sap_num_connected_sta: %d\n"
1124 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001125 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001126 hdd_ipa->pend_desc_head.next,
1127 hdd_ipa->pend_desc_head.prev,
1128 hdd_ipa->hdd_ctx,
Yun Parkb187d542016-11-14 18:10:04 -08001129 &hdd_ipa->stats,
1130 &hdd_ipa->ipv4_notifier,
1131 hdd_ipa->curr_prod_bw,
1132 hdd_ipa->curr_cons_bw,
1133 hdd_ipa->activated_fw_pipe,
1134 hdd_ipa->sap_num_connected_sta,
Yun Park46255682017-10-09 15:56:34 -07001135 (unsigned int)hdd_ipa->sta_connected);
1136
1137 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1138 "\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001139 "rx_pipe_handle: 0x%x\n"
1140 "resource_loading: %d\n"
1141 "resource_unloading: %d\n"
1142 "pending_cons_req: %d\n"
1143 "pending_event----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001144 "\tanchor.next: %pK\n"
1145 "\tanchor.prev: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001146 "\tcount: %d\n"
1147 "\tmax_size: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001148 "event_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001149 "ipa_tx_packets_diff: %d\n"
1150 "ipa_rx_packets_diff: %d\n"
1151 "ipa_p_tx_packets: %d\n"
1152 "ipa_p_rx_packets: %d\n"
1153 "stat_req_reason: %d\n",
1154 hdd_ipa->tx_pipe_handle,
1155 hdd_ipa->rx_pipe_handle,
1156 hdd_ipa->resource_loading,
1157 hdd_ipa->resource_unloading,
1158 hdd_ipa->pending_cons_req,
1159 hdd_ipa->pending_event.anchor.next,
1160 hdd_ipa->pending_event.anchor.prev,
1161 hdd_ipa->pending_event.count,
1162 hdd_ipa->pending_event.max_size,
1163 &hdd_ipa->event_lock,
1164 hdd_ipa->ipa_tx_packets_diff,
1165 hdd_ipa->ipa_rx_packets_diff,
1166 hdd_ipa->ipa_p_tx_packets,
1167 hdd_ipa->ipa_p_rx_packets,
1168 hdd_ipa->stat_req_reason);
1169
Yun Park46255682017-10-09 15:56:34 -07001170 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1171 "\ncons_pipe_in----\n"
1172 "\tsys: %pK\n"
1173 "\tdl.comp_ring_base_pa: 0x%x\n"
1174 "\tdl.comp_ring_size: %d\n"
1175 "\tdl.ce_ring_base_pa: 0x%x\n"
1176 "\tdl.ce_door_bell_pa: 0x%x\n"
1177 "\tdl.ce_ring_size: %d\n"
1178 "\tdl.num_tx_buffers: %d\n"
1179 "prod_pipe_in----\n"
1180 "\tsys: %pK\n"
1181 "\tul.rdy_ring_base_pa: 0x%x\n"
1182 "\tul.rdy_ring_size: %d\n"
1183 "\tul.rdy_ring_rp_pa: 0x%x\n"
1184 "uc_loaded: %d\n"
1185 "wdi_enabled: %d\n"
1186 "rt_debug_fill_timer: %pK\n"
1187 "rt_debug_lock: %pK\n"
1188 "ipa_lock: %pK\n",
1189 &hdd_ipa->cons_pipe_in.sys,
1190 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.comp_ring_base_pa,
1191 hdd_ipa->cons_pipe_in.u.dl.comp_ring_size,
1192 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.ce_ring_base_pa,
1193 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.ce_door_bell_pa,
1194 hdd_ipa->cons_pipe_in.u.dl.ce_ring_size,
1195 hdd_ipa->cons_pipe_in.u.dl.num_tx_buffers,
1196 &hdd_ipa->prod_pipe_in.sys,
1197 (unsigned int)hdd_ipa->prod_pipe_in.u.ul.rdy_ring_base_pa,
1198 hdd_ipa->prod_pipe_in.u.ul.rdy_ring_size,
1199 (unsigned int)hdd_ipa->prod_pipe_in.u.ul.rdy_ring_rp_pa,
1200 hdd_ipa->uc_loaded,
1201 hdd_ipa->wdi_enabled,
1202 &hdd_ipa->rt_debug_fill_timer,
1203 &hdd_ipa->rt_debug_lock,
1204 &hdd_ipa->ipa_lock);
1205
1206 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1207 "\nvdev_to_iface----");
1208 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
1209 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1210 "\n\t[%d]=%d", i, hdd_ipa->vdev_to_iface[i]);
1211 }
1212 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1213 "\nvdev_offload_enabled----");
1214 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
1215 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1216 "\n\t[%d]=%d", i, hdd_ipa->vdev_offload_enabled[i]);
1217 }
1218 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1219 "\nassoc_stas_map ----");
Yun Parkb187d542016-11-14 18:10:04 -08001220 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Yun Park46255682017-10-09 15:56:34 -07001221 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1222 "\n\t[%d]: is_reserved=%d, sta_id=%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001223 hdd_ipa->assoc_stas_map[i].is_reserved,
1224 hdd_ipa->assoc_stas_map[i].sta_id);
1225 }
1226}
1227
1228/**
1229 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1230 * @hdd_ipa: HDD IPA struct
1231 *
1232 * Dump entire struct hdd_ipa_sys_pipe
1233 *
1234 * Return: none
1235 */
1236static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1237{
1238 int i;
1239
1240 /* IPA SYS Pipes */
Yun Park46255682017-10-09 15:56:34 -07001241 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1242 "\n==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001243
1244 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1245 struct hdd_ipa_sys_pipe *sys_pipe;
Yun Park6c86a662017-10-05 16:09:15 -07001246 qdf_ipa_sys_connect_params_t *ipa_sys_params;
Yun Parkb187d542016-11-14 18:10:04 -08001247
1248 sys_pipe = &hdd_ipa->sys_pipe[i];
1249 ipa_sys_params = &sys_pipe->ipa_sys_params;
1250
Yun Park46255682017-10-09 15:56:34 -07001251 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1252 "\nsys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001253 "\tconn_hdl: 0x%x\n"
1254 "\tconn_hdl_valid: %d\n"
1255 "\tnat_en: %d\n"
1256 "\thdr_len %d\n"
1257 "\thdr_additional_const_len: %d\n"
1258 "\thdr_ofst_pkt_size_valid: %d\n"
1259 "\thdr_ofst_pkt_size: %d\n"
1260 "\thdr_little_endian: %d\n"
1261 "\tmode: %d\n"
1262 "\tclient: %d\n"
1263 "\tdesc_fifo_sz: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001264 "\tpriv: %pK\n"
1265 "\tnotify: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001266 "\tskip_ep_cfg: %d\n"
1267 "\tkeep_ipa_awake: %d\n",
1268 i,
1269 sys_pipe->conn_hdl,
1270 sys_pipe->conn_hdl_valid,
Yun Park6c86a662017-10-05 16:09:15 -07001271 QDF_IPA_SYS_PARAMS_NAT_EN(ipa_sys_params),
1272 QDF_IPA_SYS_PARAMS_HDR_LEN(ipa_sys_params),
1273 QDF_IPA_SYS_PARAMS_HDR_ADDITIONAL_CONST_LEN(
1274 ipa_sys_params),
1275 QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE_VALID(
1276 ipa_sys_params),
1277 QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE(ipa_sys_params),
1278 QDF_IPA_SYS_PARAMS_HDR_LITTLE_ENDIAN(ipa_sys_params),
1279 QDF_IPA_SYS_PARAMS_MODE(ipa_sys_params),
1280 QDF_IPA_SYS_PARAMS_CLIENT(ipa_sys_params),
1281 QDF_IPA_SYS_PARAMS_DESC_FIFO_SZ(ipa_sys_params),
1282 QDF_IPA_SYS_PARAMS_PRIV(ipa_sys_params),
1283 QDF_IPA_SYS_PARAMS_NOTIFY(ipa_sys_params),
1284 QDF_IPA_SYS_PARAMS_SKIP_EP_CFG(ipa_sys_params),
1285 QDF_IPA_SYS_PARAMS_KEEP_IPA_AWAKE(ipa_sys_params));
Yun Parkb187d542016-11-14 18:10:04 -08001286 }
1287}
1288
1289/**
1290 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1291 * @hdd_ipa: HDD IPA struct
1292 *
1293 * Dump entire struct hdd_ipa_iface_context
1294 *
1295 * Return: none
1296 */
1297static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1298{
1299 int i;
1300
1301 /* IPA Interface Contexts */
Yun Park46255682017-10-09 15:56:34 -07001302 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1303 "\n==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001304
1305 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1306 struct hdd_ipa_iface_context *iface_context;
1307
1308 iface_context = &hdd_ipa->iface_context[i];
1309
Yun Park46255682017-10-09 15:56:34 -07001310 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1311 "\niface_context[%d]----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001312 "\thdd_ipa: %pK\n"
1313 "\tadapter: %pK\n"
1314 "\ttl_context: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001315 "\tcons_client: %d\n"
1316 "\tprod_client: %d\n"
1317 "\tiface_id: %d\n"
1318 "\tsta_id: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001319 "\tinterface_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001320 "\tifa_address: 0x%x\n",
1321 i,
1322 iface_context->hdd_ipa,
1323 iface_context->adapter,
1324 iface_context->tl_context,
1325 iface_context->cons_client,
1326 iface_context->prod_client,
1327 iface_context->iface_id,
1328 iface_context->sta_id,
1329 &iface_context->interface_lock,
1330 iface_context->ifa_address);
1331 }
1332}
1333
1334/**
1335 * hdd_ipa_dump_info() - dump HDD IPA struct
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001336 * @hdd_ctx: hdd main context
Yun Parkb187d542016-11-14 18:10:04 -08001337 *
1338 * Dump entire struct hdd_ipa
1339 *
1340 * Return: none
1341 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001342void hdd_ipa_dump_info(struct hdd_context *hdd_ctx)
Yun Parkb187d542016-11-14 18:10:04 -08001343{
1344 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1345
1346 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1347 hdd_ipa_dump_sys_pipe(hdd_ipa);
1348 hdd_ipa_dump_iface_context(hdd_ipa);
1349}
1350
1351/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001352 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1353 * enabled
1354 *
1355 * This routine is called to set TX flow info if IPA is enabled
1356 *
1357 * Return: None
1358 */
1359void hdd_ipa_set_tx_flow_info(void)
1360{
Jeff Johnson49d45e62017-08-29 14:30:42 -07001361 struct hdd_adapter *adapter;
Jeff Johnsond377dce2017-10-04 10:32:42 -07001362 struct hdd_station_ctx *sta_ctx;
Jeff Johnson87251032017-08-29 13:31:11 -07001363 struct hdd_ap_ctx *hdd_ap_ctx;
Jeff Johnsonca2530c2017-09-30 18:25:40 -07001364 struct hdd_hostapd_state *hostapd_state;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001365 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1366 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1367 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1368 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1369 const char *p2pMode = "DEV";
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001370 struct hdd_context *hdd_ctx;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001371 cds_context_type *cds_ctx;
1372#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1373 uint8_t targetChannel = 0;
1374 uint8_t preAdapterChannel = 0;
1375 uint8_t channel24;
1376 uint8_t channel5;
Jeff Johnson49d45e62017-08-29 14:30:42 -07001377 struct hdd_adapter *preAdapterContext = NULL;
1378 struct hdd_adapter *adapter2_4 = NULL;
1379 struct hdd_adapter *adapter5 = NULL;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001380 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1381#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1382 struct wlan_objmgr_psoc *psoc;
1383
1384 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1385 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001386 hdd_err("HDD context is NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001387 return;
1388 }
1389
1390 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1391 if (!cds_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001392 hdd_err("Invalid CDS Context");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001393 return;
1394 }
1395
1396 psoc = hdd_ctx->hdd_psoc;
Dustin Brown920397d2017-12-13 16:27:50 -08001397
1398 hdd_for_each_adapter(hdd_ctx, adapter) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001399 switch (adapter->device_mode) {
1400 case QDF_STA_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001401 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001402 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001403 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001404 staChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001405 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001406 qdf_copy_macaddr(&staBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001407 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001408#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1409 targetChannel = staChannel;
1410#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1411 }
1412 break;
1413 case QDF_P2P_CLIENT_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001414 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001415 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001416 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001417 p2pChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001418 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001419 qdf_copy_macaddr(&p2pBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001420 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001421 p2pMode = "CLI";
1422#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1423 targetChannel = p2pChannel;
1424#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1425 }
1426 break;
1427 case QDF_P2P_GO_MODE:
1428 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1429 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001430 if (hostapd_state->bss_state == BSS_START
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001431 && hostapd_state->qdf_status ==
1432 QDF_STATUS_SUCCESS) {
Jeff Johnson01206862017-10-27 20:55:59 -07001433 p2pChannel = hdd_ap_ctx->operating_channel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001434 qdf_copy_macaddr(&p2pBssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001435 &adapter->mac_addr);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001436#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1437 targetChannel = p2pChannel;
1438#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1439 }
1440 p2pMode = "GO";
1441 break;
1442 case QDF_SAP_MODE:
1443 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1444 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001445 if (hostapd_state->bss_state == BSS_START
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001446 && hostapd_state->qdf_status ==
1447 QDF_STATUS_SUCCESS) {
Jeff Johnson01206862017-10-27 20:55:59 -07001448 apChannel = hdd_ap_ctx->operating_channel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001449 qdf_copy_macaddr(&apBssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001450 &adapter->mac_addr);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001451#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1452 targetChannel = apChannel;
1453#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1454 }
1455 break;
1456 case QDF_IBSS_MODE:
1457 default:
1458 break;
1459 }
1460#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1461 if (targetChannel) {
1462 /*
1463 * This is first adapter detected as active
1464 * set as default for none concurrency case
1465 */
1466 if (!preAdapterChannel) {
1467 /* If IPA UC data path is enabled,
1468 * target should reserve extra tx descriptors
1469 * for IPA data path.
1470 * Then host data path should allow less TX
1471 * packet pumping in case IPA
1472 * data path enabled
1473 */
1474 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1475 (QDF_SAP_MODE == adapter->device_mode)) {
1476 adapter->tx_flow_low_watermark =
1477 hdd_ctx->config->TxFlowLowWaterMark +
1478 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1479 } else {
1480 adapter->tx_flow_low_watermark =
1481 hdd_ctx->config->
1482 TxFlowLowWaterMark;
1483 }
1484 adapter->tx_flow_high_watermark_offset =
1485 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1486 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001487 adapter->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001488 hdd_ctx->config->TxFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001489 hdd_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001490 adapter->device_mode,
1491 targetChannel,
1492 adapter->tx_flow_low_watermark,
1493 adapter->tx_flow_low_watermark +
1494 adapter->tx_flow_high_watermark_offset,
1495 hdd_ctx->config->TxFlowMaxQueueDepth);
1496 preAdapterChannel = targetChannel;
1497 preAdapterContext = adapter;
1498 } else {
1499 /*
1500 * SCC, disable TX flow control for both
1501 * SCC each adapter cannot reserve dedicated
1502 * channel resource, as a result, if any adapter
1503 * blocked OS Q by flow control,
1504 * blocked adapter will lost chance to recover
1505 */
1506 if (preAdapterChannel == targetChannel) {
1507 /* Current adapter */
1508 adapter->tx_flow_low_watermark = 0;
1509 adapter->
1510 tx_flow_high_watermark_offset = 0;
1511 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001512 adapter->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001513 hdd_ctx->config->
1514 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001515 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001516 hdd_device_mode_to_string(
1517 adapter->device_mode),
1518 adapter->device_mode,
1519 targetChannel,
1520 adapter->tx_flow_low_watermark,
1521 adapter->tx_flow_low_watermark +
1522 adapter->
1523 tx_flow_high_watermark_offset,
1524 hdd_ctx->config->
1525 TxHbwFlowMaxQueueDepth);
1526
1527 if (!preAdapterContext) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001528 hdd_err("SCC: Previous adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001529 continue;
1530 }
1531
1532 /* Previous adapter */
1533 preAdapterContext->
1534 tx_flow_low_watermark = 0;
1535 preAdapterContext->
1536 tx_flow_high_watermark_offset = 0;
1537 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001538 preAdapterContext->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001539 hdd_ctx->config->
1540 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001541 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001542 hdd_device_mode_to_string(
1543 preAdapterContext->device_mode
1544 ),
1545 preAdapterContext->device_mode,
1546 targetChannel,
1547 preAdapterContext->
1548 tx_flow_low_watermark,
1549 preAdapterContext->
1550 tx_flow_low_watermark +
1551 preAdapterContext->
1552 tx_flow_high_watermark_offset,
1553 hdd_ctx->config->
1554 TxHbwFlowMaxQueueDepth);
1555 }
1556 /*
1557 * MCC, each adapter will have dedicated
1558 * resource
1559 */
1560 else {
1561 /* current channel is 2.4 */
1562 if (targetChannel <=
1563 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1564 channel24 = targetChannel;
1565 channel5 = preAdapterChannel;
1566 adapter2_4 = adapter;
1567 adapter5 = preAdapterContext;
1568 } else {
1569 /* Current channel is 5 */
1570 channel24 = preAdapterChannel;
1571 channel5 = targetChannel;
1572 adapter2_4 = preAdapterContext;
1573 adapter5 = adapter;
1574 }
1575
1576 if (!adapter5) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001577 hdd_err("MCC: 5GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001578 continue;
1579 }
1580 adapter5->tx_flow_low_watermark =
1581 hdd_ctx->config->
1582 TxHbwFlowLowWaterMark;
1583 adapter5->
1584 tx_flow_high_watermark_offset =
1585 hdd_ctx->config->
1586 TxHbwFlowHighWaterMarkOffset;
1587 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001588 adapter5->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001589 hdd_ctx->config->
1590 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001591 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001592 hdd_device_mode_to_string(
1593 adapter5->device_mode),
1594 adapter5->device_mode,
1595 channel5,
1596 adapter5->tx_flow_low_watermark,
1597 adapter5->
1598 tx_flow_low_watermark +
1599 adapter5->
1600 tx_flow_high_watermark_offset,
1601 hdd_ctx->config->
1602 TxHbwFlowMaxQueueDepth);
1603
1604 if (!adapter2_4) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001605 hdd_err("MCC: 2.4GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001606 continue;
1607 }
1608 adapter2_4->tx_flow_low_watermark =
1609 hdd_ctx->config->
1610 TxLbwFlowLowWaterMark;
1611 adapter2_4->
1612 tx_flow_high_watermark_offset =
1613 hdd_ctx->config->
1614 TxLbwFlowHighWaterMarkOffset;
1615 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001616 adapter2_4->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001617 hdd_ctx->config->
1618 TxLbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001619 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001620 hdd_device_mode_to_string(
1621 adapter2_4->device_mode),
1622 adapter2_4->device_mode,
1623 channel24,
1624 adapter2_4->
1625 tx_flow_low_watermark,
1626 adapter2_4->
1627 tx_flow_low_watermark +
1628 adapter2_4->
1629 tx_flow_high_watermark_offset,
1630 hdd_ctx->config->
1631 TxLbwFlowMaxQueueDepth);
1632
1633 }
1634 }
1635 }
1636 targetChannel = 0;
1637#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001638 }
Dustin Brown920397d2017-12-13 16:27:50 -08001639
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001640 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1641}
1642
1643/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001644 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001646 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1647 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001648 *
1649 * Return: true if IPA is enabled, false otherwise
1650 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001651static void __hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001652 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1653{
1654 struct hdd_ipa_priv *hdd_ipa;
1655
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001656 *ipa_tx_diff = 0;
1657 *ipa_rx_diff = 0;
1658
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001659 if (wlan_hdd_validate_context(hdd_ctx))
1660 return;
1661
1662 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1663
1664 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1665 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666 return;
1667 }
1668
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301669 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1671 (false == hdd_ipa->resource_loading)) {
1672 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1673 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001674 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301675 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676}
1677
1678/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001679 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1680 * @hdd_ctx: Global HDD context
1681 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1682 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1683 *
1684 * Return: true if IPA is enabled, false otherwise
1685 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001686void hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001687 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1688{
1689 cds_ssr_protect(__func__);
1690 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1691 cds_ssr_unprotect(__func__);
1692}
1693
1694/**
1695 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001696 * @adapter: network adapter
1697 * @reason: STAT REQ Reason
1698 *
1699 * Return: None
1700 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07001701static void __hdd_ipa_uc_stat_request(struct hdd_adapter *adapter,
1702 uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001703{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001704 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001705 struct hdd_ipa_priv *hdd_ipa;
1706
Yun Park637d6482016-10-05 10:51:33 -07001707 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001708 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709
Jeff Johnson399c6272017-08-30 10:51:00 -07001710 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001711
1712 if (wlan_hdd_validate_context(hdd_ctx))
1713 return;
1714
1715 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1716 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1717 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718 return;
1719 }
1720
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301721 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1723 (false == hdd_ipa->resource_loading)) {
1724 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07001725 qdf_mutex_release(&hdd_ipa->ipa_lock);
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001726 sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07001727 adapter->session_id,
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001728 WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001730 } else {
1731 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733}
1734
1735/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001736 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1737 * @adapter: network adapter
1738 * @reason: STAT REQ Reason
1739 *
1740 * Return: None
1741 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001742void hdd_ipa_uc_stat_request(struct hdd_adapter *adapter, uint8_t reason)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001743{
1744 cds_ssr_protect(__func__);
1745 __hdd_ipa_uc_stat_request(adapter, reason);
1746 cds_ssr_unprotect(__func__);
1747}
1748
Yun Park637d6482016-10-05 10:51:33 -07001749#ifdef FEATURE_METERING
1750/**
1751 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
1752 * @adapter: network adapter
1753 * @reset_stats: reset stat countis after response
1754 *
1755 * Return: None
1756 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001757void hdd_ipa_uc_sharing_stats_request(struct hdd_adapter *adapter,
Yun Park637d6482016-10-05 10:51:33 -07001758 uint8_t reset_stats)
1759{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001760 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001761 struct hdd_ipa_priv *hdd_ipa;
1762
1763 if (!adapter)
1764 return;
1765
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001766 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1767 hdd_ipa = hdd_ctx->hdd_ipa;
1768 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1769 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001770 return;
1771 }
1772
1773 HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats);
1774 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001775 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001776 qdf_mutex_release(&hdd_ipa->ipa_lock);
1777 wma_cli_set_command(
Jeff Johnson1b780e42017-10-31 14:11:45 -07001778 (int)adapter->session_id,
Yun Park637d6482016-10-05 10:51:33 -07001779 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
1780 reset_stats, VDEV_CMD);
1781 } else {
1782 qdf_mutex_release(&hdd_ipa->ipa_lock);
1783 }
1784}
1785
1786/**
1787 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
1788 * @adapter: network adapter
1789 * @set_quota: when 1, FW starts quota monitoring
1790 * @quota_bytes: quota limit in bytes
1791 *
1792 * Return: None
1793 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001794void hdd_ipa_uc_set_quota(struct hdd_adapter *adapter, uint8_t set_quota,
Yun Park637d6482016-10-05 10:51:33 -07001795 uint64_t quota_bytes)
1796{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001797 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001798 struct hdd_ipa_priv *hdd_ipa;
1799
1800 if (!adapter)
1801 return;
1802
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001803 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1804 hdd_ipa = hdd_ctx->hdd_ipa;
1805 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1806 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001807 return;
1808 }
1809
1810 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
1811 set_quota, quota_bytes);
1812
1813 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001814 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001815 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park327e7812017-02-14 15:18:10 -08001816 wma_cli_set2_command(
Jeff Johnson1b780e42017-10-31 14:11:45 -07001817 (int)adapter->session_id,
Yun Park637d6482016-10-05 10:51:33 -07001818 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
Yun Park327e7812017-02-14 15:18:10 -08001819 (set_quota ? quota_bytes&0xffffffff : 0),
1820 (set_quota ? quota_bytes>>32 : 0),
1821 VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001822 } else {
1823 qdf_mutex_release(&hdd_ipa->ipa_lock);
1824 }
1825}
1826#endif
1827
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001828/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001829 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1830 * @hdd_ipa: Global HDD IPA context
1831 * @sta_add: Should station be added
1832 * @sta_id: ID of the station being queried
1833 *
1834 * Return: true if the station was found
1835 */
1836static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1837 bool sta_add, uint8_t sta_id)
1838{
1839 bool sta_found = false;
1840 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001841
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001842 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1843 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1844 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1845 sta_found = true;
1846 break;
1847 }
1848 }
1849 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301850 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001851 "STA ID %d already exist, cannot add", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001852 return sta_found;
1853 }
1854 if (sta_add) {
1855 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1856 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1857 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1858 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1859 return sta_found;
1860 }
1861 }
1862 }
1863 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301864 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001865 "STA ID %d does not exist, cannot delete", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001866 return sta_found;
1867 }
1868 if (!sta_add) {
1869 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1870 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1871 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1872 hdd_ipa->assoc_stas_map[idx].is_reserved =
1873 false;
1874 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1875 return sta_found;
1876 }
1877 }
1878 }
1879 return sta_found;
1880}
1881
1882/**
1883 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1884 * @hdd_ipa: Global HDD IPA context
1885 *
1886 * Return: 0 on success, negative errno if error
1887 */
1888static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1889{
Yun Parkfec73dc2017-09-06 10:40:07 -07001890 int result = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07001891 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07001892 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001893
Yun Parke4239802018-01-09 11:01:40 -08001894 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Park199c2ed2017-10-02 11:24:22 -07001895
1896 if (!hdd_ipa->ipa_pipes_down) {
1897 /*
1898 * This shouldn't happen :
1899 * IPA WDI Pipes are already activated
1900 */
1901 WARN_ON(1);
1902 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
1903 "IPA WDI Pipes are already activated");
1904 goto end;
1905 }
Yun Parkfec73dc2017-09-06 10:40:07 -07001906
Yun Parkb4f591d2017-03-29 15:51:01 -07001907 result = cdp_ipa_enable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301909 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001910 "Enable PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001911 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001912 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001913
Yun Park777d7242017-03-30 15:38:33 -07001914 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Leo Change3e49442015-10-26 20:07:13 -07001915 hdd_ipa->ipa_pipes_down = false;
Yun Parkb4f591d2017-03-29 15:51:01 -07001916
1917 cdp_ipa_enable_autonomy(soc, (struct cdp_pdev *)pdev);
1918
Yun Parkfec73dc2017-09-06 10:40:07 -07001919end:
Yun Parke4239802018-01-09 11:01:40 -08001920 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07001921 hdd_ipa->ipa_pipes_down);
Yun Park199c2ed2017-10-02 11:24:22 -07001922
Yun Parkfec73dc2017-09-06 10:40:07 -07001923 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001924}
1925
1926/**
1927 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1928 * @hdd_ipa: Global HDD IPA context
1929 *
1930 * Return: 0 on success, negative errno if error
1931 */
1932static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1933{
Yun Parkb4f591d2017-03-29 15:51:01 -07001934 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1935 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkfec73dc2017-09-06 10:40:07 -07001936 int result = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937
Yun Parke4239802018-01-09 11:01:40 -08001938 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Park199c2ed2017-10-02 11:24:22 -07001939
1940 if (hdd_ipa->ipa_pipes_down) {
1941 /*
1942 * This shouldn't happen :
1943 * IPA WDI Pipes are already deactivated
1944 */
1945 WARN_ON(1);
1946 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
1947 "IPA WDI Pipes are already deactivated");
1948 goto end;
1949 }
Leo Change3e49442015-10-26 20:07:13 -07001950
Yun Parkb4f591d2017-03-29 15:51:01 -07001951 cdp_ipa_disable_autonomy(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001952
Yun Parkb4f591d2017-03-29 15:51:01 -07001953 result = cdp_ipa_disable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301955 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001956 "Disable WDI PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001957 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958 }
1959
Yun Parkfec73dc2017-09-06 10:40:07 -07001960 hdd_ipa->ipa_pipes_down = true;
1961
1962end:
Yun Parke4239802018-01-09 11:01:40 -08001963 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07001964 hdd_ipa->ipa_pipes_down);
1965 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001966}
1967
1968/**
1969 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1970 * @hdd_ipa: Global HDD IPA context
1971 *
1972 * Return: 0 on success, negative errno if error
1973 */
1974static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1975{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001976 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07001977
Yun Parke4239802018-01-09 11:01:40 -08001978 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07001979
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001980 hdd_ipa->activated_fw_pipe = 0;
1981 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001982
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983 /* If RM feature enabled
1984 * Request PROD Resource first
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07001985 * PROD resource may return sync or async manners
1986 */
Yun Parkb4f591d2017-03-29 15:51:01 -07001987 if (hdd_ipa_is_rm_enabled(hdd_ctx)) {
Yun Park4cab6ee2015-10-27 11:43:40 -07001988 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1989 /* RM PROD request sync return
1990 * enable pipe immediately
1991 */
1992 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301993 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001994 "IPA WDI Pipe activation failed");
Yun Park4cab6ee2015-10-27 11:43:40 -07001995 hdd_ipa->resource_loading = false;
1996 return -EBUSY;
1997 }
Sravan Kumar Kairamc76f28a2017-07-25 19:03:40 +05301998 } else {
1999 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park199c2ed2017-10-02 11:24:22 -07002000 "IPA WDI Pipe activation deferred");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002001 }
2002 } else {
2003 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07002004 * Just enabled all the PIPEs
2005 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302007 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002008 "IPA WDI Pipe activation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002009 hdd_ipa->resource_loading = false;
2010 return -EBUSY;
2011 }
2012 hdd_ipa->resource_loading = false;
2013 }
Yun Park4cab6ee2015-10-27 11:43:40 -07002014
Yun Parke4239802018-01-09 11:01:40 -08002015 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002016 return 0;
2017}
2018
2019/**
2020 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
2021 * @hdd_ipa: Global HDD IPA context
2022 *
2023 * Return: None
2024 */
2025static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
2026{
Leo Changfdb45c32016-10-28 11:09:23 -07002027 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07002028 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029
Yun Parke4239802018-01-09 11:01:40 -08002030 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07002031
Yun Parkb4f591d2017-03-29 15:51:01 -07002032 if (!pdev) {
Yun Park7c4f31b2016-11-30 10:09:21 -08002033 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2034 QDF_ASSERT(0);
2035 return;
2036 }
2037
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038 hdd_ipa->resource_unloading = true;
Yun Park777d7242017-03-30 15:38:33 -07002039 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Yun Parkb4f591d2017-03-29 15:51:01 -07002040 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW RX PIPE");
2041 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, false);
2042 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW TX PIPE");
2043 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, true);
Yun Parkfec73dc2017-09-06 10:40:07 -07002044
Yun Parke4239802018-01-09 11:01:40 -08002045 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: IPA WDI Pipes deactivated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046}
2047
2048/**
2049 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2050 * @context: User context registered with TL (the IPA Global context is
2051 * registered
2052 * @rxpkt: Packet containing the notification
2053 * @staid: ID of the station associated with the packet
2054 *
2055 * Return: None
2056 */
2057static void
Yun Park6c86a662017-10-05 16:09:15 -07002058hdd_ipa_uc_rm_notify_handler(void *context, qdf_ipa_rm_event_t event)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002059{
2060 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302061 QDF_STATUS status = QDF_STATUS_SUCCESS;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002062 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002063
2064 /*
2065 * When SSR is going on or driver is unloading, just return.
2066 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002067 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302068 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002069 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002070
Yun Parkb4f591d2017-03-29 15:51:01 -07002071 if (!hdd_ipa_is_rm_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002072 return;
2073
Yun Park46255682017-10-09 15:56:34 -07002074 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event code %d",
2075 event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076
2077 switch (event) {
2078 case IPA_RM_RESOURCE_GRANTED:
2079 /* Differed RM Granted */
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302080 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081 if ((false == hdd_ipa->resource_unloading) &&
2082 (!hdd_ipa->activated_fw_pipe)) {
2083 hdd_ipa_uc_enable_pipes(hdd_ipa);
2084 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302085 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002086 break;
2087
2088 case IPA_RM_RESOURCE_RELEASED:
2089 /* Differed RM Released */
2090 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002091 break;
2092
2093 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302094 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07002095 "invalid event code %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002096 break;
2097 }
2098}
2099
2100/**
2101 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2102 * @hdd_ipa: Global HDD IPA context
2103 * @event: IPA resource manager event to be deferred
2104 *
2105 * This function is called when a resource manager event is received
2106 * from firmware in interrupt context. This function will defer the
2107 * handling to the OL RX thread
2108 *
2109 * Return: None
2110 */
2111static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2112{
Yun Park6c86a662017-10-05 16:09:15 -07002113 qdf_ipa_rm_event_t event;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002114 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2115 struct uc_rm_work_struct, work);
2116 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2117 struct hdd_ipa_priv, uc_rm_work);
2118
2119 cds_ssr_protect(__func__);
2120 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002121 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07002122 "posted event %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002123
2124 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2125 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002126}
2127
2128/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002129 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
Yun Parkb4f591d2017-03-29 15:51:01 -07002130 * @hdd_ipa: hdd ipa local context
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002131 *
2132 * Will handle IPA UC image loaded indication comes from IPA kernel
2133 *
2134 * Return: None
2135 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002136static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *hdd_ipa)
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002137{
Yun Parkb4f591d2017-03-29 15:51:01 -07002138 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2139 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002140 struct hdd_context *hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07002141 QDF_STATUS status;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002142
Yun Park46255682017-10-09 15:56:34 -07002143 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC READY");
Yun Parkb4f591d2017-03-29 15:51:01 -07002144 if (true == hdd_ipa->uc_loaded) {
Yun Park46255682017-10-09 15:56:34 -07002145 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "UC already loaded");
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002146 return;
2147 }
2148
Yun Parkb4f591d2017-03-29 15:51:01 -07002149 hdd_ctx = hdd_ipa->hdd_ctx;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002150
Yun Parkb4f591d2017-03-29 15:51:01 -07002151 /* Connect pipe */
2152 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
2153 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
2154 hdd_ipa_wdi_meter_notifier_cb,
2155 hdd_ctx->config->IpaDescSize,
2156 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
2157 &hdd_ipa->tx_pipe_handle,
2158 &hdd_ipa->rx_pipe_handle);
2159 if (status) {
2160 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2161 "Failure to setup IPA pipes (status=%d)",
2162 status);
2163 return;
2164 }
2165
2166 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002167
2168 /* If already any STA connected, enable IPA/FW PIPEs */
Yun Parkb4f591d2017-03-29 15:51:01 -07002169 if (hdd_ipa->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002170 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002171 "Client already connected, enable IPA/FW PIPEs");
Yun Parkb4f591d2017-03-29 15:51:01 -07002172 hdd_ipa_uc_handle_first_con(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002173 }
2174}
2175
2176/**
Yun Park637d6482016-10-05 10:51:33 -07002177 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2178 * @hdd_ctx: Global HDD context
2179 * @op_msg: operation message received from firmware
2180 *
2181 * Return: QDF_STATUS enumeration
2182 */
2183#ifdef FEATURE_METERING
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002184static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002185 struct op_msg_type *op_msg)
2186{
2187 struct op_msg_type *msg = op_msg;
2188 struct ipa_uc_sharing_stats *uc_sharing_stats;
2189 struct ipa_uc_quota_rsp *uc_quota_rsp;
2190 struct ipa_uc_quota_ind *uc_quota_ind;
2191 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002192 struct hdd_adapter *adapter;
Yun Park637d6482016-10-05 10:51:33 -07002193
2194 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2195
2196 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2197 /* fill-up ipa_uc_sharing_stats structure from FW */
2198 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2199 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2200
2201 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2202 sizeof(struct ipa_uc_sharing_stats));
2203
2204 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2205
2206 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2207 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2208 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2209 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2210 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2211 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2212 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2213 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2214 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2215 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2216 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2217 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2218 /* received set quota response */
2219 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2220 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2221
2222 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2223 sizeof(struct ipa_uc_quota_rsp));
2224
2225 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2226 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2227 "%s: success=%d, quota_bytes=%llu",
2228 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2229 hdd_ipa->ipa_quota_rsp.success,
2230 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2231 hdd_ipa->ipa_quota_rsp.quota_lo);
2232 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2233 /* hit quota limit */
2234 uc_quota_ind = (struct ipa_uc_quota_ind *)
2235 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2236
2237 hdd_ipa->ipa_quota_ind.quota_bytes =
2238 uc_quota_ind->quota_bytes;
2239
2240 /* send quota exceeded indication to IPA */
2241 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2242 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2243 hdd_ipa->ipa_quota_ind.quota_bytes);
2244
2245 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2246 if (adapter)
2247 ipa_broadcast_wdi_quota_reach_ind(
2248 adapter->dev->ifindex,
2249 uc_quota_ind->quota_bytes);
2250 else
2251 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2252 "Failed quota_reach_ind: NULL adapter");
2253 } else {
2254 return QDF_STATUS_E_INVAL;
2255 }
2256
2257 return QDF_STATUS_SUCCESS;
2258}
2259#else
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002260static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002261 struct op_msg_type *op_msg)
2262{
2263 return QDF_STATUS_E_INVAL;
2264}
2265#endif
2266
Yun Park657c7d72017-06-07 15:44:59 -07002267#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0))
2268/* older versions had a typo */
2269#define num_bam_int_in_non_running_state num_bam_int_in_non_runnning_state
2270#endif
2271
Yun Park637d6482016-10-05 10:51:33 -07002272/**
Yun Park46255682017-10-09 15:56:34 -07002273 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
2274 * @event: IPA WLAN event to be converted to a string
2275 *
2276 * Return: ASCII string representing the IPA WLAN event
2277 */
Yun Park6c86a662017-10-05 16:09:15 -07002278static inline char *hdd_ipa_wlan_event_to_str(qdf_ipa_wlan_event_t event)
Yun Park46255682017-10-09 15:56:34 -07002279{
2280 switch (event) {
2281 CASE_RETURN_STRING(WLAN_CLIENT_CONNECT);
2282 CASE_RETURN_STRING(WLAN_CLIENT_DISCONNECT);
2283 CASE_RETURN_STRING(WLAN_CLIENT_POWER_SAVE_MODE);
2284 CASE_RETURN_STRING(WLAN_CLIENT_NORMAL_MODE);
2285 CASE_RETURN_STRING(SW_ROUTING_ENABLE);
2286 CASE_RETURN_STRING(SW_ROUTING_DISABLE);
2287 CASE_RETURN_STRING(WLAN_AP_CONNECT);
2288 CASE_RETURN_STRING(WLAN_AP_DISCONNECT);
2289 CASE_RETURN_STRING(WLAN_STA_CONNECT);
2290 CASE_RETURN_STRING(WLAN_STA_DISCONNECT);
2291 CASE_RETURN_STRING(WLAN_CLIENT_CONNECT_EX);
2292 default:
2293 return "UNKNOWN";
2294 }
2295}
2296
2297/**
2298 * hdd_ipa_print_session_info - Print IPA session info
2299 * @hdd_ipa: HDD IPA local context
2300 *
2301 * Return: None
2302 */
2303static void hdd_ipa_print_session_info(struct hdd_ipa_priv *hdd_ipa)
2304{
2305 uint8_t session_id;
2306 int device_mode;
2307 struct ipa_uc_pending_event *event = NULL, *next = NULL;
2308 struct hdd_ipa_iface_context *iface_context = NULL;
2309 int i;
2310
2311 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2312 "\n==== IPA SESSION INFO ====\n"
2313 "NUM IFACE: %d\n"
2314 "RM STATE: %d\n"
2315 "ACTIVATED FW PIPE: %d\n"
2316 "SAP NUM STAs: %d\n"
2317 "STA CONNECTED: %d\n"
2318 "CONCURRENT MODE: %s\n"
2319 "RSC LOADING: %d\n"
2320 "RSC UNLOADING: %d\n"
2321 "PENDING CONS REQ: %d\n"
2322 "IPA PIPES DOWN: %d\n"
2323 "IPA UC LOADED: %d\n"
2324 "IPA WDI ENABLED: %d\n"
2325 "NUM SEND MSG: %d\n"
2326 "NUM FREE MSG: %d\n",
2327 hdd_ipa->num_iface,
2328 hdd_ipa->rm_state,
2329 hdd_ipa->activated_fw_pipe,
2330 hdd_ipa->sap_num_connected_sta,
2331 hdd_ipa->sta_connected,
2332 (hdd_ipa->hdd_ctx->mcc_mode ? "MCC" : "SCC"),
2333 hdd_ipa->resource_loading,
2334 hdd_ipa->resource_unloading,
2335 hdd_ipa->pending_cons_req,
2336 hdd_ipa->ipa_pipes_down,
2337 hdd_ipa->uc_loaded,
2338 hdd_ipa->wdi_enabled,
2339 (unsigned int)hdd_ipa->stats.num_send_msg,
2340 (unsigned int)hdd_ipa->stats.num_free_msg);
2341
2342 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2343 iface_context = &hdd_ipa->iface_context[i];
2344 if (!iface_context || !iface_context->adapter)
2345 continue;
2346
Jeff Johnson1b780e42017-10-31 14:11:45 -07002347 session_id = iface_context->adapter->session_id;
Yun Park46255682017-10-09 15:56:34 -07002348 if (session_id >= CSR_ROAM_SESSION_MAX)
2349 continue;
2350
2351 device_mode = iface_context->adapter->device_mode;
2352 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2353 "\nIFACE[%d]: session:%d, sta_id:%d, mode:%s, offload:%d",
2354 i, session_id,
2355 iface_context->sta_id,
2356 hdd_device_mode_to_string(device_mode),
2357 hdd_ipa->vdev_offload_enabled[session_id]);
2358 }
2359
2360 for (i = 0; i < IPA_WLAN_EVENT_MAX; i++)
2361 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2362 "\nEVENT[%d]=%d",
2363 i, hdd_ipa->stats.event[i]);
2364
2365 i = 0;
2366 qdf_list_peek_front(&hdd_ipa->pending_event,
2367 (qdf_list_node_t **)&event);
2368 while (event != NULL) {
2369 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2370 "\nPENDING EVENT[%d]: DEV:%s, EVT:%s, sta_id:%d, MAC:%pM",
2371 i, event->adapter->dev->name,
2372 hdd_ipa_wlan_event_to_str(event->type),
2373 event->sta_id, event->mac_addr);
2374
2375 qdf_list_peek_next(&hdd_ipa->pending_event,
2376 (qdf_list_node_t *)event, (qdf_list_node_t **)&next);
2377 event = next;
2378 next = NULL;
2379 i++;
2380 }
2381}
2382
2383/**
2384 * hdd_ipa_print_txrx_stats - Print HDD IPA TX/RX stats
2385 * @hdd_ipa: HDD IPA local context
2386 *
2387 * Return: None
2388 */
2389static void hdd_ipa_print_txrx_stats(struct hdd_ipa_priv *hdd_ipa)
2390{
2391 int i;
2392 struct hdd_ipa_iface_context *iface_context = NULL;
2393
2394 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2395 "\n==== HDD IPA TX/RX STATS ====\n"
2396 "NUM RM GRANT: %llu\n"
2397 "NUM RM RELEASE: %llu\n"
2398 "NUM RM GRANT IMM: %llu\n"
2399 "NUM CONS PERF REQ: %llu\n"
2400 "NUM PROD PERF REQ: %llu\n"
2401 "NUM RX DROP: %llu\n"
2402 "NUM EXCP PKT: %llu\n"
2403 "NUM TX FWD OK: %llu\n"
2404 "NUM TX FWD ERR: %llu\n"
2405 "NUM TX DESC Q CNT: %llu\n"
2406 "NUM TX DESC ERROR: %llu\n"
2407 "NUM TX COMP CNT: %llu\n"
2408 "NUM TX QUEUED: %llu\n"
2409 "NUM TX DEQUEUED: %llu\n"
2410 "NUM MAX PM QUEUE: %llu\n"
2411 "TX REF CNT: %d\n"
2412 "SUSPENDED: %d\n"
2413 "PEND DESC HEAD: %pK\n"
2414 "TX DESC LIST: %pK\n"
2415 "FREE TX DESC HEAD: %pK\n",
2416 hdd_ipa->stats.num_rm_grant,
2417 hdd_ipa->stats.num_rm_release,
2418 hdd_ipa->stats.num_rm_grant_imm,
2419 hdd_ipa->stats.num_cons_perf_req,
2420 hdd_ipa->stats.num_prod_perf_req,
2421 hdd_ipa->stats.num_rx_drop,
2422 hdd_ipa->stats.num_rx_excep,
2423 hdd_ipa->stats.num_tx_fwd_ok,
2424 hdd_ipa->stats.num_tx_fwd_err,
2425 hdd_ipa->stats.num_tx_desc_q_cnt,
2426 hdd_ipa->stats.num_tx_desc_error,
2427 hdd_ipa->stats.num_tx_comp_cnt,
2428 hdd_ipa->stats.num_tx_queued,
2429 hdd_ipa->stats.num_tx_dequeued,
2430 hdd_ipa->stats.num_max_pm_queue,
2431 hdd_ipa->tx_ref_cnt.counter,
2432 hdd_ipa->suspended,
2433 &hdd_ipa->pend_desc_head,
2434 hdd_ipa->tx_desc_list,
2435 &hdd_ipa->free_tx_desc_head);
2436
2437 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2438 iface_context = &hdd_ipa->iface_context[i];
2439 if (!iface_context || !iface_context->adapter)
2440 continue;
2441
2442 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2443 "IFACE[%d]: TX:%llu, TX DROP:%llu, TX ERR:%llu, TX CAC DROP:%llu, RX IPA EXCEP:%llu",
2444 i,
2445 iface_context->stats.num_tx,
2446 iface_context->stats.num_tx_drop,
2447 iface_context->stats.num_tx_err,
2448 iface_context->stats.num_tx_cac_drop,
2449 iface_context->stats.num_rx_ipa_excep);
2450 }
2451}
2452
2453/**
2454 * hdd_ipa_print_fw_wdi_stats - Print WLAN FW WDI stats
2455 * @hdd_ipa: HDD IPA local context
2456 *
2457 * Return: None
2458 */
2459static void hdd_ipa_print_fw_wdi_stats(struct hdd_ipa_priv *hdd_ipa,
2460 struct ipa_uc_fw_stats *uc_fw_stat)
2461{
2462 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2463 "\n==== WLAN FW WDI TX STATS ====\n"
2464 "COMP RING BASE: 0x%x\n"
2465 "COMP RING SIZE: %d\n"
2466 "COMP RING DBELL : 0x%x\n"
2467 "COMP RING DBELL IND VAL : %d\n"
2468 "COMP RING DBELL CACHED VAL : %d\n"
2469 "PKTS ENQ : %d\n"
2470 "PKTS COMP : %d\n"
2471 "IS SUSPEND : %d\n",
2472 uc_fw_stat->tx_comp_ring_base,
2473 uc_fw_stat->tx_comp_ring_size,
2474 uc_fw_stat->tx_comp_ring_dbell_addr,
2475 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2476 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2477 uc_fw_stat->tx_pkts_enqueued,
2478 uc_fw_stat->tx_pkts_completed,
2479 uc_fw_stat->tx_is_suspend);
2480
2481 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2482 "\n==== WLAN FW WDI RX STATS ====\n"
2483 "IND RING BASE: 0x%x\n"
2484 "IND RING SIZE: %d\n"
2485 "IND RING DBELL : 0x%x\n"
2486 "IND RING DBELL IND VAL : %d\n"
2487 "IND RING DBELL CACHED VAL : %d\n"
2488 "RDY IND ADDR : 0x%x\n"
2489 "RDY IND CACHE VAL : %d\n"
2490 "RFIL IND : %d\n"
2491 "NUM PKT INDICAT : %d\n"
2492 "BUF REFIL : %d\n"
2493 "NUM DROP NO SPC : %d\n"
2494 "NUM DROP NO BUF : %d\n"
2495 "IS SUSPND : %d\n",
2496 uc_fw_stat->rx_ind_ring_base,
2497 uc_fw_stat->rx_ind_ring_size,
2498 uc_fw_stat->rx_ind_ring_dbell_addr,
2499 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2500 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2501 uc_fw_stat->rx_ind_ring_rdidx_addr,
2502 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2503 uc_fw_stat->rx_refill_idx,
2504 uc_fw_stat->rx_num_pkts_indicated,
2505 uc_fw_stat->rx_buf_refilled,
2506 uc_fw_stat->rx_num_ind_drop_no_space,
2507 uc_fw_stat->rx_num_ind_drop_no_buf,
2508 uc_fw_stat->rx_is_suspend);
2509}
2510
2511/**
2512 * hdd_ipa_print_ipa_wdi_stats - Print IPA WDI stats
2513 * @hdd_ipa: HDD IPA local context
2514 *
2515 * Return: None
2516 */
2517static void hdd_ipa_print_ipa_wdi_stats(struct hdd_ipa_priv *hdd_ipa)
2518{
2519 struct IpaHwStatsWDIInfoData_t ipa_stat;
2520
2521 ipa_get_wdi_stats(&ipa_stat);
2522
2523 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2524 "\n==== IPA WDI TX STATS ====\n"
2525 "NUM PROCD : %d\n"
2526 "CE DBELL : 0x%x\n"
2527 "NUM DBELL FIRED : %d\n"
2528 "COMP RNG FULL : %d\n"
2529 "COMP RNG EMPT : %d\n"
2530 "COMP RNG USE HGH : %d\n"
2531 "COMP RNG USE LOW : %d\n"
2532 "BAM FIFO FULL : %d\n"
2533 "BAM FIFO EMPT : %d\n"
2534 "BAM FIFO USE HGH : %d\n"
2535 "BAM FIFO USE LOW : %d\n"
2536 "NUM DBELL : %d\n"
2537 "NUM UNEXP DBELL : %d\n"
2538 "NUM BAM INT HDL : 0x%x\n"
2539 "NUM BAM INT NON-RUN : 0x%x\n"
2540 "NUM QMB INT HDL : 0x%x\n",
2541 ipa_stat.tx_ch_stats.num_pkts_processed,
2542 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2543 ipa_stat.tx_ch_stats.num_db_fired,
2544 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2545 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2546 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2547 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2548 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2549 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2550 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2551 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2552 ipa_stat.tx_ch_stats.num_db,
2553 ipa_stat.tx_ch_stats.num_unexpected_db,
2554 ipa_stat.tx_ch_stats.num_bam_int_handled,
2555 ipa_stat.tx_ch_stats.
2556#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
2557 num_bam_int_in_non_running_state,
2558#else
2559 num_bam_int_in_non_runnning_state,
2560#endif
2561 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2562
2563 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2564 "\n==== IPA WDI RX STATS ====\n"
2565 "MAX OST PKT : %d\n"
2566 "NUM PKT PRCSD : %d\n"
2567 "RNG RP : 0x%x\n"
2568 "IND RNG FULL : %d\n"
2569 "IND RNG EMPT : %d\n"
2570 "IND RNG USE HGH : %d\n"
2571 "IND RNG USE LOW : %d\n"
2572 "BAM FIFO FULL : %d\n"
2573 "BAM FIFO EMPT : %d\n"
2574 "BAM FIFO USE HGH : %d\n"
2575 "BAM FIFO USE LOW : %d\n"
2576 "NUM DB : %d\n"
2577 "NUM UNEXP DB : %d\n"
2578 "NUM BAM INT HNDL : 0x%x\n",
2579 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2580 ipa_stat.rx_ch_stats.num_pkts_processed,
2581 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2582 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2583 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2584 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2585 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2586 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2587 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2588 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2589 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2590 ipa_stat.rx_ch_stats.num_db,
2591 ipa_stat.rx_ch_stats.num_unexpected_db,
2592 ipa_stat.rx_ch_stats.num_bam_int_handled);
2593}
2594
2595/**
2596 * hdd_ipa_uc_info() - Print IPA uC resource and session information
2597 * @adapter: network adapter
2598 *
2599 * Return: None
2600 */
2601void hdd_ipa_uc_info(struct hdd_context *hdd_ctx)
2602{
2603 struct hdd_ipa_priv *hdd_ipa;
2604
2605 hdd_ipa = hdd_ctx->hdd_ipa;
2606
2607 if (!hdd_ipa) {
2608 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2609 "HDD IPA context is NULL");
2610 return;
2611 }
2612
2613 /* IPA session info */
2614 hdd_ipa_print_session_info(hdd_ipa);
2615}
2616
2617/**
2618 * hdd_ipa_uc_stat() - Print IPA uC stats
2619 * @adapter: network adapter
2620 *
2621 * Return: None
2622 */
2623void hdd_ipa_uc_stat(struct hdd_adapter *adapter)
2624{
2625 struct hdd_context *hdd_ctx;
2626 struct hdd_ipa_priv *hdd_ipa;
2627
2628 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2629 hdd_ipa = hdd_ctx->hdd_ipa;
2630
2631 if (!hdd_ipa) {
2632 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2633 "HDD IPA context is NULL");
2634 return;
2635 }
2636
2637 /* HDD IPA TX/RX stats */
2638 hdd_ipa_print_txrx_stats(hdd_ipa);
2639 /* IPA WDI stats */
2640 hdd_ipa_print_ipa_wdi_stats(hdd_ipa);
2641 /* WLAN FW WDI stats */
2642 hdd_ipa_uc_stat_request(adapter, HDD_IPA_UC_STAT_REASON_DEBUG);
2643}
2644
2645/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002646 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2647 * @op_msg: operation message received from firmware
2648 * @usr_ctxt: user context registered with TL (we register the HDD Global
2649 * context)
2650 *
2651 * Return: None
2652 */
2653static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2654{
2655 struct op_msg_type *msg = op_msg;
2656 struct ipa_uc_fw_stats *uc_fw_stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002657 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002658 struct hdd_context *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302659 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002660
2661 if (!op_msg || !usr_ctxt) {
Yun Park46255682017-10-09 15:56:34 -07002662 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "INVALID ARG");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002663 return;
2664 }
2665
2666 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302667 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07002668 "INVALID OPCODE %d", msg->op_code);
jiadd91a6842017-08-01 14:46:02 +08002669 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002670 return;
2671 }
2672
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002673 hdd_ctx = (struct hdd_context *) usr_ctxt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002674
2675 /*
2676 * When SSR is going on or driver is unloading, just return.
2677 */
2678 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302679 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302680 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002681 return;
2682 }
2683
2684 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2685
Govind Singhb6a89772016-08-12 11:23:35 +05302686 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002687 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002688
2689 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2690 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302691 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002692 hdd_ipa->activated_fw_pipe++;
2693 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2694 hdd_ipa->resource_loading = false;
Yun Park777d7242017-03-30 15:38:33 -07002695 complete(&hdd_ipa->ipa_resource_comp);
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002696 if (hdd_ipa->wdi_enabled == false) {
2697 hdd_ipa->wdi_enabled = true;
2698 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2699 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2700 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002701 }
Yun Parka4bb37c2017-12-08 16:14:22 -08002702 hdd_ipa_uc_proc_pending_event(hdd_ipa, true);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002703 if (hdd_ipa->pending_cons_req)
2704 ipa_rm_notify_completion(
2705 IPA_RM_RESOURCE_GRANTED,
2706 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002707 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002708 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302709 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002710 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002711 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302712 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002713 hdd_ipa->activated_fw_pipe--;
2714 if (!hdd_ipa->activated_fw_pipe) {
Yun Park777d7242017-03-30 15:38:33 -07002715 /*
2716 * Async return success from FW
2717 * Disable/suspend all the PIPEs
2718 */
Yun Parka4bb37c2017-12-08 16:14:22 -08002719 hdd_ipa->resource_unloading = false;
2720 complete(&hdd_ipa->ipa_resource_comp);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002721 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002722 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2723 ipa_rm_release_resource(
2724 IPA_RM_RESOURCE_WLAN_PROD);
Yun Parka4bb37c2017-12-08 16:14:22 -08002725 hdd_ipa_uc_proc_pending_event(hdd_ipa, false);
Yun Park5b635012015-12-02 15:05:01 -08002726 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002727 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302728 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002729 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002730 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002731 uc_fw_stat = (struct ipa_uc_fw_stats *)
Yun Park46255682017-10-09 15:56:34 -07002732 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002733
Yun Park46255682017-10-09 15:56:34 -07002734 /* WLAN FW WDI stats */
2735 hdd_ipa_print_fw_wdi_stats(hdd_ipa, uc_fw_stat);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002736 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2737 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2738 /* STATs from FW */
2739 uc_fw_stat = (struct ipa_uc_fw_stats *)
2740 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302741 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2743 uc_fw_stat->tx_pkts_completed,
2744 hdd_ipa->ipa_p_tx_packets);
2745 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2746 (uc_fw_stat->rx_num_ind_drop_no_space +
2747 uc_fw_stat->rx_num_ind_drop_no_buf +
2748 uc_fw_stat->rx_num_pkts_indicated),
2749 hdd_ipa->ipa_p_rx_packets);
2750
2751 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2752 hdd_ipa->ipa_p_rx_packets =
2753 (uc_fw_stat->rx_num_ind_drop_no_space +
2754 uc_fw_stat->rx_num_ind_drop_no_buf +
2755 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302756 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002757 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2758 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2759 hdd_ipa_uc_loaded_handler(hdd_ipa);
2760 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002761 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2762 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2763 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002764 }
Yun Park8957d802017-01-25 12:27:29 -08002765
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302766 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002767}
2768
2769
2770/**
2771 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2772 * @adapter: device adapter instance
2773 * @offload_type: MCC or SCC
2774 * @enable: TX offload enable or disable
2775 *
2776 * Return: none
2777 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07002778static void hdd_ipa_uc_offload_enable_disable(struct hdd_adapter *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002779 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002780{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002781 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002782 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002783 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002784 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002785
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002786 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002787 return;
2788
Yun Park8292dcb2016-10-07 16:46:06 -07002789 iface_context = adapter->ipa_context;
Jeff Johnson1b780e42017-10-31 14:11:45 -07002790 session_id = adapter->session_id;
Yun Park8292dcb2016-10-07 16:46:06 -07002791
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002792 if (!iface_context) {
2793 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2794 "Interface context is NULL");
2795 return;
2796 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08002797 if (session_id >= CSR_ROAM_SESSION_MAX) {
2798 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2799 "invalid session id: %d", session_id);
2800 return;
2801 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002802 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park199c2ed2017-10-02 11:24:22 -07002803 /*
2804 * This shouldn't happen :
2805 * IPA offload status is already set as desired
2806 */
2807 WARN_ON(1);
2808 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
Yun Parkb4f591d2017-03-29 15:51:01 -07002809 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002810 "IPA offload status is already set",
2811 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002812 return;
2813 }
2814
Jeff Johnson1b780e42017-10-31 14:11:45 -07002815 if (wlan_hdd_validate_session_id(adapter->session_id)) {
Yun Park4540e862016-11-10 16:30:06 -08002816 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2817 "invalid session id: %d, offload_type=%d, enable=%d",
Jeff Johnson1b780e42017-10-31 14:11:45 -07002818 adapter->session_id, offload_type, enable);
Yun Park4540e862016-11-10 16:30:06 -08002819 return;
2820 }
2821
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302822 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002823 sizeof(ipa_offload_enable_disable));
2824 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002825 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002826 ipa_offload_enable_disable.enable = enable;
2827
Yun Park199c2ed2017-10-02 11:24:22 -07002828 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07002829 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002830 ipa_offload_enable_disable.offload_type,
2831 ipa_offload_enable_disable.vdev_id,
2832 ipa_offload_enable_disable.enable);
2833
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302834 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002835 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07002836 adapter->session_id, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302837 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07002838 "Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2839 ipa_offload_enable_disable.offload_type,
2840 ipa_offload_enable_disable.vdev_id,
2841 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002842 } else {
2843 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002844 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002845 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002846 }
2847}
2848
2849/**
2850 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2851 * @work: uC OP work
2852 *
2853 * Return: None
2854 */
2855static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2856{
2857 struct op_msg_type *msg;
2858 struct uc_op_work_struct *uc_op_work = container_of(work,
2859 struct uc_op_work_struct, work);
2860 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2861
2862 cds_ssr_protect(__func__);
2863
2864 msg = uc_op_work->msg;
2865 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002866 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07002867 "posted msg %d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002868
2869 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2870
2871 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002872}
2873
2874/**
2875 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2876 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2877 * @op_msg: operation message received from firmware
2878 * @hdd_ctx: Global HDD context
2879 *
2880 * Return: None
2881 */
2882static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2883{
2884 struct hdd_ipa_priv *hdd_ipa;
2885 struct op_msg_type *msg;
2886 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302887 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002888
2889 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302890 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002891 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002892
2893 msg = (struct op_msg_type *)op_msg;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002894 hdd_ipa = ((struct hdd_context *)hdd_ctx)->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002895
2896 if (unlikely(!hdd_ipa))
2897 goto end;
2898
2899 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Yun Parkb4f591d2017-03-29 15:51:01 -07002900 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid OP Code (%d)",
2901 msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002902 goto end;
2903 }
2904
2905 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2906 if (uc_op_work->msg)
2907 /* When the same uC OPCODE is already pended, just return */
2908 goto end;
2909
2910 uc_op_work->msg = msg;
2911 schedule_work(&uc_op_work->work);
2912 return;
2913
2914end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302915 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002916}
2917
2918/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002919 * hdd_ipa_init_uc_op_work - init ipa uc op work
2920 * @work: struct work_struct
2921 * @work_handler: work_handler
2922 *
2923 * Return: none
2924 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002925static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002926 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002927{
2928 INIT_WORK(work, work_handler);
2929}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002930
Yun Park637d6482016-10-05 10:51:33 -07002931#ifdef FEATURE_METERING
2932/**
2933 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2934 * IPA calls to get WLAN stats or set quota limit.
2935 * @priv: pointer to private data registered with IPA (we register a
2936 *» pointer to the global IPA context)
2937 * @evt: the IPA event which triggered the callback
2938 * @data: data associated with the event
2939 *
2940 * Return: None
2941 */
Yun Park6c86a662017-10-05 16:09:15 -07002942static void __hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Park637d6482016-10-05 10:51:33 -07002943 void *data)
2944{
2945 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002946 struct hdd_adapter *adapter = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07002947 qdf_ipa_get_wdi_sap_stats_t *wdi_sap_stats;
2948 qdf_ipa_set_wifi_quota_t *ipa_set_quota;
Yun Park637d6482016-10-05 10:51:33 -07002949 int ret = 0;
2950
2951 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2952 return;
2953
2954 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2955
2956 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2957
2958 switch (evt) {
2959 case IPA_GET_WDI_SAP_STATS:
2960 /* fill-up ipa_get_wdi_sap_stats structure after getting
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07002961 * ipa_uc_fw_stats from FW
2962 */
Yun Park637d6482016-10-05 10:51:33 -07002963 wdi_sap_stats = data;
2964
2965 if (!adapter) {
2966 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2967 "IPA uC share stats failed - no adapter");
Yun Park6c86a662017-10-05 16:09:15 -07002968 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) =
2969 0;
Yun Park637d6482016-10-05 10:51:33 -07002970 return;
2971 }
2972
2973 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
Yun Park637d6482016-10-05 10:51:33 -07002974 hdd_ipa_uc_sharing_stats_request(adapter,
Yun Park6c86a662017-10-05 16:09:15 -07002975 QDF_IPA_GET_WDI_SAP_STATS_RESET_STATS(wdi_sap_stats));
Yun Park637d6482016-10-05 10:51:33 -07002976 ret = wait_for_completion_timeout(
2977 &hdd_ipa->ipa_uc_sharing_stats_comp,
2978 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2979 if (!ret) {
2980 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2981 "IPA uC share stats request timed out");
Yun Park6c86a662017-10-05 16:09:15 -07002982 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
2983 = 0;
Yun Park637d6482016-10-05 10:51:33 -07002984 } else {
Yun Park6c86a662017-10-05 16:09:15 -07002985 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
2986 = 1;
Yun Park637d6482016-10-05 10:51:33 -07002987
Yun Park6c86a662017-10-05 16:09:15 -07002988 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(wdi_sap_stats)
2989 = hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2990 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(wdi_sap_stats)
2991 = hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2992 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(wdi_sap_stats)
2993 = hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2994 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(wdi_sap_stats)
2995 = hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
2996 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(wdi_sap_stats)
2997 = hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
2998 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(wdi_sap_stats)
2999 = hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
3000 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(wdi_sap_stats)
3001 = hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
3002 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(wdi_sap_stats)
3003 = hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
Yun Park637d6482016-10-05 10:51:33 -07003004 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
3005 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
3006 "IPA_GET_WDI_SAP_STATS",
Yun Park6c86a662017-10-05 16:09:15 -07003007 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(
3008 wdi_sap_stats),
3009 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(
3010 wdi_sap_stats),
3011 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(
3012 wdi_sap_stats),
3013 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(
3014 wdi_sap_stats),
3015 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(
3016 wdi_sap_stats),
3017 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(
3018 wdi_sap_stats),
3019 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(
3020 wdi_sap_stats),
3021 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(
3022 wdi_sap_stats),
3023 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(
3024 wdi_sap_stats));
Yun Park637d6482016-10-05 10:51:33 -07003025 }
3026 break;
3027 case IPA_SET_WIFI_QUOTA:
3028 /* get ipa_set_wifi_quota structure from IPA and pass to FW
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07003029 * through quota_exceeded field in ipa_uc_fw_stats
3030 */
Yun Park637d6482016-10-05 10:51:33 -07003031 ipa_set_quota = data;
3032
3033 if (!adapter) {
3034 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3035 "IPA uC set quota failed - no adapter");
3036 ipa_set_quota->set_valid = 0;
3037 return;
3038 }
3039
Yun Park777d7242017-03-30 15:38:33 -07003040 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
Yun Park637d6482016-10-05 10:51:33 -07003041 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
3042 ipa_set_quota->quota_bytes);
3043
3044 ret = wait_for_completion_timeout(
3045 &hdd_ipa->ipa_uc_set_quota_comp,
3046 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
3047 if (!ret) {
3048 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3049 "IPA uC set quota request timed out");
Yun Park6c86a662017-10-05 16:09:15 -07003050 QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = 0;
Yun Park637d6482016-10-05 10:51:33 -07003051 } else {
Yun Park6c86a662017-10-05 16:09:15 -07003052 QDF_IPA_SET_WIFI_QUOTA_BYTES(ipa_set_quota) =
Yun Park637d6482016-10-05 10:51:33 -07003053 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
3054 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
Yun Park6c86a662017-10-05 16:09:15 -07003055 QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) =
Yun Park637d6482016-10-05 10:51:33 -07003056 hdd_ipa->ipa_quota_rsp.success;
3057 }
3058
3059 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
3060 ipa_set_quota->quota_bytes,
3061 ipa_set_quota->set_valid);
3062 break;
3063 }
3064}
3065
3066/**
3067 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
3068 * IPA calls to get WLAN stats or set quota limit.
3069 * @priv: pointer to private data registered with IPA (we register a
Yun Parkb4f591d2017-03-29 15:51:01 -07003070 * pointer to the global IPA context)
Yun Park637d6482016-10-05 10:51:33 -07003071 * @evt: the IPA event which triggered the callback
3072 * @data: data associated with the event
3073 *
3074 * Return: None
3075 */
Yun Park6c86a662017-10-05 16:09:15 -07003076static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Park637d6482016-10-05 10:51:33 -07003077 void *data)
3078{
3079 cds_ssr_protect(__func__);
3080 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
3081 cds_ssr_unprotect(__func__);
3082}
3083
Yun Parkb4f591d2017-03-29 15:51:01 -07003084static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07003085{
Yun Park637d6482016-10-05 10:51:33 -07003086 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
3087 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
3088}
3089#else
Yun Parkb4f591d2017-03-29 15:51:01 -07003090static void hdd_ipa_wdi_meter_notifier_cb(void)
3091{
3092}
3093
3094static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07003095{
3096}
3097#endif
3098
Rajeev Kumar217f2172016-01-06 18:11:55 -08003099/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003100 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
3101 * @hdd_ctx: Global HDD context
3102 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003103 * This function is called to update IPA pipe configuration with resources
3104 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
3105 * (cds_enable)
3106 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303107 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003108 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003109QDF_STATUS hdd_ipa_uc_ol_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003110{
Yun Parkb4f591d2017-03-29 15:51:01 -07003111 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07003112 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08003113 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkb4f591d2017-03-29 15:51:01 -07003114 uint8_t i;
3115 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003116
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003117 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3118 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003119
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08003120 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003121
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003122 /* Do only IPA Pipe specific configuration here. All one time
3123 * initialization wrt IPA UC shall in hdd_ipa_init and those need
3124 * to be reinit at SSR shall in be SSR deinit / reinit functions.
3125 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003126 if (!pdev || !soc) {
3127 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkb4f591d2017-03-29 15:51:01 -07003128 status = QDF_STATUS_E_FAILURE;
Yun Parkbaa62862017-01-18 13:43:34 -08003129 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003130 }
Yun Parka4bb37c2017-12-08 16:14:22 -08003131
3132 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3133 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3134 hdd_ipa->vdev_offload_enabled[i] = false;
3135 }
3136
Yun Parkb4f591d2017-03-29 15:51:01 -07003137 if (cdp_ipa_get_resource(soc, (struct cdp_pdev *)pdev)) {
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003138 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
3139 "IPA UC resource alloc fail");
Yun Park199c2ed2017-10-02 11:24:22 -07003140 status = QDF_STATUS_E_FAILURE;
3141 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003142 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003143
Yun Parkb4f591d2017-03-29 15:51:01 -07003144 if (true == hdd_ipa->uc_loaded) {
3145 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
3146 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
3147 hdd_ipa_wdi_meter_notifier_cb,
3148 hdd_ctx->config->IpaDescSize,
3149 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
3150 &hdd_ipa->tx_pipe_handle,
3151 &hdd_ipa->rx_pipe_handle);
3152 if (status) {
Yun Parkbaa62862017-01-18 13:43:34 -08003153 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07003154 "Failure to setup IPA pipes (status=%d)",
3155 status);
Yun Park199c2ed2017-10-02 11:24:22 -07003156 status = QDF_STATUS_E_FAILURE;
3157 goto fail_return;
Yun Parkbaa62862017-01-18 13:43:34 -08003158 }
Yun Park637d6482016-10-05 10:51:33 -07003159
Yun Parkb4f591d2017-03-29 15:51:01 -07003160 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
3161 hdd_ipa_init_metering(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003162 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003163
Yun Parkb4f591d2017-03-29 15:51:01 -07003164 cdp_ipa_register_op_cb(soc, (struct cdp_pdev *)pdev,
Yun Parkbaa62862017-01-18 13:43:34 -08003165 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
3166
Yun Parkb4f591d2017-03-29 15:51:01 -07003167 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
3168 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
Yun Parka4bb37c2017-12-08 16:14:22 -08003169 hdd_ipa_uc_fw_op_event_handler);
Yun Parkb4f591d2017-03-29 15:51:01 -07003170 hdd_ipa->uc_op_work[i].msg = NULL;
3171 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003172
Yun Parkbaa62862017-01-18 13:43:34 -08003173fail_return:
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08003174 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: status=%d", status);
Yun Parkb4f591d2017-03-29 15:51:01 -07003175 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003176}
3177
Leo Change3e49442015-10-26 20:07:13 -07003178/**
Yun Parkd8fb1a82017-10-13 16:48:20 -07003179 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
3180 * @hdd_ipa: pointer to HDD IPA struct
3181 *
3182 * Return: none
3183 */
3184static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
3185{
3186 struct ipa_uc_pending_event *pending_event = NULL;
3187
3188 while (qdf_list_remove_front(&hdd_ipa->pending_event,
3189 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
3190 qdf_mem_free(pending_event);
3191}
3192
3193/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303194 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
3195 * @hdd_ctx: Global HDD context
3196 *
3197 * Return: 0 on success, negativer errno on error
3198 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003199int hdd_ipa_uc_ol_deinit(struct hdd_context *hdd_ctx)
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303200{
3201 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
Yun Park6edb2172018-01-14 00:18:05 -08003202 int i, ret = 0;
Yun Parkb4f591d2017-03-29 15:51:01 -07003203 QDF_STATUS status;
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303204
Yun Parke4239802018-01-09 11:01:40 -08003205 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003206
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303207 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3208 return ret;
3209
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05303210 if (!hdd_ipa->ipa_pipes_down)
3211 hdd_ipa_uc_disable_pipes(hdd_ipa);
3212
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303213 if (true == hdd_ipa->uc_loaded) {
Yun Parkb4f591d2017-03-29 15:51:01 -07003214 status = cdp_ipa_cleanup(cds_get_context(QDF_MODULE_ID_SOC),
3215 hdd_ipa->tx_pipe_handle,
3216 hdd_ipa->rx_pipe_handle);
3217 if (status) {
3218 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3219 "Failure to cleanup IPA pipes (status=%d)",
3220 status);
Yun Park6edb2172018-01-14 00:18:05 -08003221 ret = -EFAULT;
Yun Parkb4f591d2017-03-29 15:51:01 -07003222 }
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303223 }
3224
Yun Parka4bb37c2017-12-08 16:14:22 -08003225 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07003226 hdd_ipa_cleanup_pending_event(hdd_ipa);
Yun Parka4bb37c2017-12-08 16:14:22 -08003227 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07003228
Yun Park6edb2172018-01-14 00:18:05 -08003229 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
3230 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
3231 qdf_mem_free(hdd_ipa->uc_op_work[i].msg);
3232 hdd_ipa->uc_op_work[i].msg = NULL;
3233 }
3234
Yun Parke4239802018-01-09 11:01:40 -08003235 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: ret=%d", ret);
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303236 return ret;
3237}
3238
3239/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003240 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07003241 * @hdd_ctx: hdd main context
3242 *
3243 * Force shutdown IPA pipe
3244 * Independent of FW pipe status, IPA pipe shutdonw progress
3245 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3246 * independent from FW pipe status
3247 *
3248 * Return: NONE
3249 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003250static void __hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07003251{
3252 struct hdd_ipa_priv *hdd_ipa;
3253
Yun Parke4239802018-01-09 11:01:40 -08003254 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003255
Leo Change3e49442015-10-26 20:07:13 -07003256 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
3257 return;
3258
3259 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
3260 if (false == hdd_ipa->ipa_pipes_down) {
Yun Park46255682017-10-09 15:56:34 -07003261 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Parkb4f591d2017-03-29 15:51:01 -07003262 "IPA pipes are not down yet, force shutdown");
Leo Change3e49442015-10-26 20:07:13 -07003263 hdd_ipa_uc_disable_pipes(hdd_ipa);
3264 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003265 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb4f591d2017-03-29 15:51:01 -07003266 "IPA pipes are down, do nothing");
Leo Change3e49442015-10-26 20:07:13 -07003267 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003268
Yun Parke4239802018-01-09 11:01:40 -08003269 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Leo Change3e49442015-10-26 20:07:13 -07003270}
3271
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003273 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
3274 * __hdd_ipa_uc_force_pipe_shutdown
3275 * @hdd_ctx: hdd main context
3276 *
3277 * Force shutdown IPA pipe
3278 * Independent of FW pipe status, IPA pipe shutdonw progress
3279 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3280 * independent from FW pipe status
3281 *
3282 * Return: NONE
3283 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003284void hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003285{
3286 cds_ssr_protect(__func__);
3287 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
3288 cds_ssr_unprotect(__func__);
3289}
3290
3291/**
Govind Singh9c58eba2016-09-02 16:23:06 +05303292 * hdd_ipa_msg_free_fn() - Free an IPA message
3293 * @buff: pointer to the IPA message
3294 * @len: length of the IPA message
3295 * @type: type of IPA message
3296 *
3297 * Return: None
3298 */
3299static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
3300{
Srinivas Girigowda97852372017-03-06 16:52:59 -08003301 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05303302 ghdd_ipa->stats.num_free_msg++;
3303 qdf_mem_free(buff);
3304}
3305
Govind Singh9c58eba2016-09-02 16:23:06 +05303306/**
jge62037862016-12-09 10:44:33 +08003307 * hdd_ipa_uc_send_evt() - send event to ipa
3308 * @hdd_ctx: pointer to hdd context
3309 * @type: event type
3310 * @mac_addr: pointer to mac address
3311 *
3312 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303313 *
3314 * Return: 0 - Success
3315 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003316static int hdd_ipa_uc_send_evt(struct hdd_adapter *adapter,
Yun Park6c86a662017-10-05 16:09:15 -07003317 qdf_ipa_wlan_event_t type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303318{
jge62037862016-12-09 10:44:33 +08003319 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07003320 qdf_ipa_msg_meta_t meta;
3321 qdf_ipa_wlan_msg_t *msg;
Govind Singh9c58eba2016-09-02 16:23:06 +05303322 int ret = 0;
jge62037862016-12-09 10:44:33 +08003323
Yun Park6c86a662017-10-05 16:09:15 -07003324 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
3325 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
jge62037862016-12-09 10:44:33 +08003326 if (msg == NULL) {
3327 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3328 "msg allocation failed");
3329 return -ENOMEM;
3330 }
3331
Yun Park6c86a662017-10-05 16:09:15 -07003332 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
3333 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), adapter->dev->name,
jge62037862016-12-09 10:44:33 +08003334 IPA_RESOURCE_NAME_MAX);
Yun Park6c86a662017-10-05 16:09:15 -07003335 memcpy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, ETH_ALEN);
Yun Park199c2ed2017-10-02 11:24:22 -07003336 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Yun Park6c86a662017-10-05 16:09:15 -07003337 QDF_IPA_WLAN_MSG_NAME(msg), QDF_IPA_MSG_META_MSG_TYPE(&meta));
3338 ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
jge62037862016-12-09 10:44:33 +08003339 if (ret) {
3340 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3341 "%s: Evt: %d fail:%d",
Yun Park6c86a662017-10-05 16:09:15 -07003342 QDF_IPA_WLAN_MSG_NAME(msg),
3343 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
jge62037862016-12-09 10:44:33 +08003344 qdf_mem_free(msg);
3345 return ret;
3346 }
3347
3348 hdd_ipa->stats.num_send_msg++;
3349
3350 return ret;
3351}
3352
3353/**
3354 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3355 * @hdd_ctx: pointer to hdd adapter
3356 *
3357 * Send disconnect client event to IPA driver during SSR
3358 *
3359 * Return: 0 - Success
3360 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003361static int hdd_ipa_uc_disconnect_client(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003362{
3363 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3364 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303365 int i;
3366
Yun Parke4239802018-01-09 11:01:40 -08003367 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Govind Singh9c58eba2016-09-02 16:23:06 +05303368 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003369 if (qdf_is_macaddr_broadcast(&adapter->sta_info[i].sta_mac))
Govind Singh9c58eba2016-09-02 16:23:06 +05303370 continue;
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003371 if ((adapter->sta_info[i].in_use) &&
3372 (!adapter->sta_info[i].is_deauth_in_progress) &&
jge62037862016-12-09 10:44:33 +08003373 hdd_ipa->sap_num_connected_sta) {
3374 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003375 adapter->sta_info[i].sta_mac.bytes);
jge62037862016-12-09 10:44:33 +08003376 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303377 }
3378 }
Yun Parke4239802018-01-09 11:01:40 -08003379 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07003380 hdd_ipa->sap_num_connected_sta);
Govind Singh9c58eba2016-09-02 16:23:06 +05303381
3382 return ret;
3383}
3384
3385/**
jge62037862016-12-09 10:44:33 +08003386 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3387 * @hdd_ctx: pointer to hdd adapter
3388 *
3389 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303390 *
3391 * Return: 0 - Success
3392 */
jge62037862016-12-09 10:44:33 +08003393
Jeff Johnson49d45e62017-08-29 14:30:42 -07003394static int hdd_ipa_uc_disconnect_ap(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003395{
3396 int ret = 0;
3397
Yun Parke4239802018-01-09 11:01:40 -08003398 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003399 if (adapter->ipa_context) {
jge62037862016-12-09 10:44:33 +08003400 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3401 adapter->dev->dev_addr);
Yun Parkfec73dc2017-09-06 10:40:07 -07003402 }
Yun Parke4239802018-01-09 11:01:40 -08003403 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
jge62037862016-12-09 10:44:33 +08003404
3405 return ret;
3406}
3407
jge62037862016-12-09 10:44:33 +08003408/**
3409 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3410 * @hdd_ctx: pointer to hdd adapter
3411 *
3412 * Send disconnect sta event to IPA driver during SSR
3413 *
3414 * Return: 0 - Success
3415 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003416static int hdd_ipa_uc_disconnect_sta(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003417{
Jeff Johnsond377dce2017-10-04 10:32:42 -07003418 struct hdd_station_ctx *sta_ctx;
jge62037862016-12-09 10:44:33 +08003419 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3420 int ret = 0;
3421
Yun Parke4239802018-01-09 11:01:40 -08003422 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003423 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003424 hdd_ipa->sta_connected) {
Jeff Johnsond377dce2017-10-04 10:32:42 -07003425 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
jge62037862016-12-09 10:44:33 +08003426 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Jeff Johnsond377dce2017-10-04 10:32:42 -07003427 sta_ctx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003428 }
Yun Parke4239802018-01-09 11:01:40 -08003429 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
jge62037862016-12-09 10:44:33 +08003430
3431 return ret;
3432}
jge62037862016-12-09 10:44:33 +08003433
3434/**
3435 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3436 * @hdd_ctx: pointer to hdd context
3437 *
3438 * Send disconnect event to IPA driver during SSR
3439 *
3440 * Return: 0 - Success
3441 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003442static int hdd_ipa_uc_disconnect(struct hdd_context *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303443{
Jeff Johnson49d45e62017-08-29 14:30:42 -07003444 struct hdd_adapter *adapter;
Govind Singh9c58eba2016-09-02 16:23:06 +05303445 int ret = 0;
3446
Dustin Brown920397d2017-12-13 16:27:50 -08003447 hdd_for_each_adapter(hdd_ctx, adapter) {
jge62037862016-12-09 10:44:33 +08003448 if (adapter->device_mode == QDF_SAP_MODE) {
3449 hdd_ipa_uc_disconnect_client(adapter);
3450 hdd_ipa_uc_disconnect_ap(adapter);
3451 } else if (adapter->device_mode == QDF_STA_MODE) {
3452 hdd_ipa_uc_disconnect_sta(adapter);
3453 }
Govind Singh9c58eba2016-09-02 16:23:06 +05303454 }
3455
3456 return ret;
3457}
3458
3459/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003460 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003461 *
3462 * Deinit basic IPA UC host side to be in sync reloaded FW during
3463 * SSR
3464 *
3465 * Return: 0 - Success
3466 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003467static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003468{
3469 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3470 int idx;
3471 struct hdd_ipa_iface_context *iface_context;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003472 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003473
Yun Parke4239802018-01-09 11:01:40 -08003474 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003475
Arun Khandavallicc544b32017-01-30 19:52:16 +05303476 if (!hdd_ipa)
3477 return 0;
3478
3479 hdd_ctx = hdd_ipa->hdd_ctx;
3480 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003481 return 0;
3482
jge62037862016-12-09 10:44:33 +08003483 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303484 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003485
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003486 /* Clean up HDD IPA interfaces */
3487 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3488 (idx < HDD_IPA_MAX_IFACE); idx++) {
3489 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003490 if (iface_context->adapter && iface_context->adapter->magic ==
3491 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003492 hdd_ipa_cleanup_iface(iface_context);
3493 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003494 hdd_ipa->num_iface = 0;
Yun Parka4bb37c2017-12-08 16:14:22 -08003495
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003496 /* After SSR, wlan driver reloads FW again. But we need to protect
3497 * IPA submodule during SSR transient state. So deinit basic IPA
3498 * UC host side to be in sync with reloaded FW during SSR
3499 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003500
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303501 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003502 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3503 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3504 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3505 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303506 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003507
Guolei Bianca144d82016-11-10 11:07:42 +08003508 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3509 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3510
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003511 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
3512 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
3513 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
3514 hdd_ipa->uc_op_work[idx].msg = NULL;
3515 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003516
Yun Parke4239802018-01-09 11:01:40 -08003517 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003518 return 0;
3519}
3520
3521/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003522 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3523 *
3524 * Deinit basic IPA UC host side to be in sync reloaded FW during
3525 * SSR
3526 *
3527 * Return: 0 - Success
3528 */
3529int hdd_ipa_uc_ssr_deinit(void)
3530{
3531 int ret;
3532
3533 cds_ssr_protect(__func__);
3534 ret = __hdd_ipa_uc_ssr_deinit();
3535 cds_ssr_unprotect(__func__);
3536
3537 return ret;
3538}
3539
3540/**
3541 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003542 *
3543 * Init basic IPA UC host side to be in sync with reloaded FW after
3544 * SSR to resume IPA UC operations
3545 *
3546 * Return: 0 - Success
3547 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003548static int __hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003549{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003550
Arun Khandavallicc544b32017-01-30 19:52:16 +05303551 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3552 int i;
3553 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303554
Yun Parke4239802018-01-09 11:01:40 -08003555 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003556
Arun Khandavallicc544b32017-01-30 19:52:16 +05303557 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3558 return 0;
3559
Arun Khandavallicc544b32017-01-30 19:52:16 +05303560 /* Create the interface context */
3561 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3562 iface_context = &hdd_ipa->iface_context[i];
3563 iface_context->hdd_ipa = hdd_ipa;
3564 iface_context->cons_client =
3565 hdd_ipa_adapter_2_client[i].cons_client;
3566 iface_context->prod_client =
3567 hdd_ipa_adapter_2_client[i].prod_client;
3568 iface_context->iface_id = i;
3569 iface_context->adapter = NULL;
3570 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05303571
3572 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3573 hdd_ipa->resource_loading = false;
3574 hdd_ipa->resource_unloading = false;
3575 hdd_ipa->sta_connected = 0;
3576 hdd_ipa->ipa_pipes_down = true;
3577 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303578 }
3579
Yun Parke4239802018-01-09 11:01:40 -08003580 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003581 return 0;
3582}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003583
3584/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003585 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3586 *
3587 * Init basic IPA UC host side to be in sync with reloaded FW after
3588 * SSR to resume IPA UC operations
3589 *
3590 * Return: 0 - Success
3591 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003592int hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003593{
3594 int ret;
3595
3596 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303597 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003598 cds_ssr_unprotect(__func__);
3599
3600 return ret;
3601}
3602
3603/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003604 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3605 * @work: scheduled work
3606 *
3607 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3608 * not want to immediately release the wake lock since the system
3609 * would then potentially try to suspend when there is a healthy data
3610 * rate. Deferred work is scheduled and this function handles the
3611 * work. When this function is called, if the IPA resource is still
3612 * released then we release the wake lock.
3613 *
3614 * Return: None
3615 */
3616static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3617{
3618 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3619 struct hdd_ipa_priv,
3620 wake_lock_work);
3621
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303622 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003623
3624 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3625 goto end;
3626
3627 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303628 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003629 WIFI_POWER_EVENT_WAKELOCK_IPA);
3630
3631end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303632 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003633}
3634
3635/**
3636 * hdd_ipa_rm_request() - Request resource from IPA
3637 * @hdd_ipa: Global HDD IPA context
3638 *
3639 * Return: 0 on success, negative errno on error
3640 */
3641static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3642{
3643 int ret = 0;
3644
3645 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3646 return 0;
3647
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303648 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003649
3650 switch (hdd_ipa->rm_state) {
3651 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303652 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003653 return 0;
3654 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303655 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003656 return -EINPROGRESS;
3657 case HDD_IPA_RM_RELEASED:
3658 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3659 break;
3660 }
3661
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303662 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003663
Yun Park6c86a662017-10-05 16:09:15 -07003664 ret = qdf_ipa_rm_inactivity_timer_request_resource(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003665 IPA_RM_RESOURCE_WLAN_PROD);
3666
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303667 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003668 if (ret == 0) {
3669 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3670 hdd_ipa->stats.num_rm_grant_imm++;
3671 }
3672
3673 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3674 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303675 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003676 WIFI_POWER_EVENT_WAKELOCK_IPA);
3677 hdd_ipa->wake_lock_released = false;
3678 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303679 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003680
3681 return ret;
3682}
3683
3684/**
3685 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3686 * @hdd_ipa: Global HDD IPA context
3687 *
3688 * Return: 0 if resources released, negative errno otherwise
3689 */
3690static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3691{
3692 int ret = 0;
3693
3694 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3695 return 0;
3696
3697 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3698 return -EAGAIN;
3699
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303700 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003701
Nirav Shahcbc6d722016-03-01 16:24:53 +05303702 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303703 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003704 return -EAGAIN;
3705 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303706 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003707
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303708 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003709 switch (hdd_ipa->rm_state) {
3710 case HDD_IPA_RM_GRANTED:
3711 break;
3712 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303713 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003714 return -EINPROGRESS;
3715 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303716 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003717 return 0;
3718 }
3719
3720 /* IPA driver returns immediately so set the state here to avoid any
3721 * race condition.
3722 */
3723 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3724 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303725 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003726
Yun Park6c86a662017-10-05 16:09:15 -07003727 ret = qdf_ipa_rm_inactivity_timer_release_resource(
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003728 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003729
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303730 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731 if (unlikely(ret != 0)) {
3732 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3733 WARN_ON(1);
Yun Park199c2ed2017-10-02 11:24:22 -07003734 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
3735 "ipa_rm_inactivity_timer_release_resource returnied fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003736 }
3737
3738 /*
3739 * If wake_lock is released immediately, kernel would try to suspend
3740 * immediately as well, Just avoid ping-pong between suspend-resume
3741 * while there is healthy amount of data transfer going on by
3742 * releasing the wake_lock after some delay.
3743 */
3744 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3745 msecs_to_jiffies
3746 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3747
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303748 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003749
3750 return ret;
3751}
3752
3753/**
3754 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3755 * @user_data: user data registered with IPA
3756 * @event: the IPA resource manager event that occurred
3757 * @data: the data associated with the event
3758 *
3759 * Return: None
3760 */
Yun Park6c86a662017-10-05 16:09:15 -07003761static void hdd_ipa_rm_notify(void *user_data, qdf_ipa_rm_event_t event,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003762 unsigned long data)
3763{
3764 struct hdd_ipa_priv *hdd_ipa = user_data;
3765
3766 if (unlikely(!hdd_ipa))
3767 return;
3768
3769 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3770 return;
3771
Srinivas Girigowda97852372017-03-06 16:52:59 -08003772 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003773
3774 switch (event) {
3775 case IPA_RM_RESOURCE_GRANTED:
3776 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3777 /* RM Notification comes with ISR context
3778 * it should be serialized into work queue to avoid
3779 * ISR sleep problem
3780 */
3781 hdd_ipa->uc_rm_work.event = event;
3782 schedule_work(&hdd_ipa->uc_rm_work.work);
3783 break;
3784 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303785 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003786 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303787 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003788 hdd_ipa->stats.num_rm_grant++;
3789 break;
3790
3791 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003792 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003793 hdd_ipa->resource_unloading = false;
3794 break;
3795
3796 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303797 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003798 break;
3799 }
3800}
3801
3802/**
3803 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3804 *
3805 * Callback function registered with IPA that is called when IPA wants
3806 * to release the WLAN consumer resource
3807 *
3808 * Return: 0 if the request is granted, negative errno otherwise
3809 */
3810static int hdd_ipa_rm_cons_release(void)
3811{
3812 return 0;
3813}
3814
3815/**
3816 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3817 *
3818 * Callback function registered with IPA that is called when IPA wants
3819 * to access the WLAN consumer resource
3820 *
3821 * Return: 0 if the request is granted, negative errno otherwise
3822 */
3823static int hdd_ipa_rm_cons_request(void)
3824{
Yun Park4d8b60a2015-10-22 13:59:32 -07003825 int ret = 0;
3826
3827 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303828 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003829 "IPA resource loading in progress");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003830 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003831 ret = -EINPROGRESS;
3832 } else if (ghdd_ipa->resource_unloading) {
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 unloading in progress");
Yun Park4d8b60a2015-10-22 13:59:32 -07003835 ghdd_ipa->pending_cons_req = true;
3836 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003837 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003838
3839 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003840}
3841
3842/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003843 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003844 * @hdd_ctx: Global HDD context
3845 * @tx_packets: Number of packets transmitted in the last sample period
3846 * @rx_packets: Number of packets received in the last sample period
3847 *
3848 * Return: 0 on success, negative errno on error
3849 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07003850static int __hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx,
3851 uint64_t tx_packets,
3852 uint64_t rx_packets)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003853{
3854 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003855 struct hdd_ipa_priv *hdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07003856 qdf_ipa_rm_perf_profile_t profile;
Yun Parkb4f591d2017-03-29 15:51:01 -07003857 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858 int ret;
3859
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003860 if (wlan_hdd_validate_context(hdd_ctx))
3861 return 0;
3862
3863 hdd_ipa = hdd_ctx->hdd_ipa;
3864
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003865 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3866 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3867 return 0;
3868
3869 memset(&profile, 0, sizeof(profile));
3870
3871 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3872 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3873 else if (tx_packets >
3874 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3875 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3876 else
3877 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3878
3879 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3880 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3881 else if (rx_packets >
3882 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3883 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3884 else
3885 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3886
Yun Parkec845302016-12-15 09:22:57 -08003887 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003888 "CONS perf curr: %d, next: %d",
3889 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003890 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003891 "PROD perf curr: %d, next: %d",
3892 hdd_ipa->curr_prod_bw, next_prod_bw);
3893
3894 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003895 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003896 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003897 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS,
3898 next_cons_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003899 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003900 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003901
3902 return ret;
3903 }
3904 hdd_ipa->curr_cons_bw = next_cons_bw;
3905 hdd_ipa->stats.num_cons_perf_req++;
3906 }
3907
3908 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003909 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003910 hdd_ipa->curr_prod_bw, next_prod_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003911 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD,
3912 next_prod_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003913 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003914 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003915 return ret;
3916 }
3917 hdd_ipa->curr_prod_bw = next_prod_bw;
3918 hdd_ipa->stats.num_prod_perf_req++;
3919 }
3920
3921 return 0;
3922}
3923
3924/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003925 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3926 * @hdd_ctx: Global HDD context
3927 * @tx_packets: Number of packets transmitted in the last sample period
3928 * @rx_packets: Number of packets received in the last sample period
3929 *
3930 * Return: 0 on success, negative errno on error
3931 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003932int hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003933 uint64_t rx_packets)
3934{
3935 int ret;
3936
3937 cds_ssr_protect(__func__);
3938 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3939 cds_ssr_unprotect(__func__);
3940
3941 return ret;
3942}
3943
3944/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003945 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3946 * @work: struct work_struct
3947 * @work_handler: work_handler
3948 *
3949 * Return: none
3950 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003951static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3952 work_func_t work_handler)
3953{
3954 INIT_WORK(work, work_handler);
3955}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003956
3957/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003958 * hdd_ipa_setup_rm() - Setup IPA resource management
3959 * @hdd_ipa: Global HDD IPA context
3960 *
3961 * Return: 0 on success, negative errno on error
3962 */
3963static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3964{
Yun Park6c86a662017-10-05 16:09:15 -07003965 qdf_ipa_rm_create_params_t create_params = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003966 int ret;
3967
3968 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3969 return 0;
3970
Rajeev Kumar217f2172016-01-06 18:11:55 -08003971 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3972 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003973 memset(&create_params, 0, sizeof(create_params));
Yun Park6c86a662017-10-05 16:09:15 -07003974 QDF_IPA_RM_CREATE_PARAMS_NAME(&create_params) =
3975 IPA_RM_RESOURCE_WLAN_PROD;
3976 QDF_IPA_RM_CREATE_PARAMS_USER_DATA(&create_params) =
3977 hdd_ipa;
3978 QDF_IPA_RM_CREATE_PARAMS_NOTIFY_CB(&create_params) =
3979 hdd_ipa_rm_notify;
3980 QDF_IPA_RM_CREATE_PARAMS_FLOOR_VOLTAGE(&create_params) =
3981 IPA_VOLTAGE_SVS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982
Yun Park6c86a662017-10-05 16:09:15 -07003983 ret = qdf_ipa_rm_create_resource(&create_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003984 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303985 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003986 "Create RM resource failed: %d", ret);
3987 goto setup_rm_fail;
3988 }
3989
3990 memset(&create_params, 0, sizeof(create_params));
Yun Park6c86a662017-10-05 16:09:15 -07003991 QDF_IPA_RM_CREATE_PARAMS_NAME(&create_params) =
3992 IPA_RM_RESOURCE_WLAN_CONS;
3993 QDF_IPA_RM_CREATE_PARAMS_REQUEST_RESOURCE(&create_params) =
3994 hdd_ipa_rm_cons_request;
3995 QDF_IPA_RM_CREATE_PARAMS_RELEASE_RESOURCE(&create_params) =
3996 hdd_ipa_rm_cons_release;
3997 QDF_IPA_RM_CREATE_PARAMS_FLOOR_VOLTAGE(&create_params) =
3998 IPA_VOLTAGE_SVS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003999
Yun Park6c86a662017-10-05 16:09:15 -07004000 ret = qdf_ipa_rm_create_resource(&create_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004001 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304002 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004003 "Create RM CONS resource failed: %d", ret);
4004 goto delete_prod;
4005 }
4006
4007 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
4008 IPA_RM_RESOURCE_APPS_CONS);
4009
Yun Park6c86a662017-10-05 16:09:15 -07004010 ret = qdf_ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
4011 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304013 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004014 ret);
4015 goto timer_init_failed;
4016 }
4017
4018 /* Set the lowest bandwidth to start with */
4019 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
4020
4021 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304022 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004023 "Set perf level failed: %d", ret);
4024 goto set_perf_failed;
4025 }
4026
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304027 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
4029 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304030 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004031 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
4032 hdd_ipa->wake_lock_released = true;
4033 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
4034
4035 return ret;
4036
4037set_perf_failed:
4038 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4039
4040timer_init_failed:
4041 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4042
4043delete_prod:
4044 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4045
4046setup_rm_fail:
4047 return ret;
4048}
4049
4050/**
4051 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
4052 * @hdd_ipa: Global HDD IPA context
4053 *
4054 * Destroys all resources associated with the IPA resource manager
4055 *
4056 * Return: None
4057 */
4058static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
4059{
4060 int ret;
4061
4062 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4063 return;
4064
4065 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304066 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004067
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004068 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304069 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004070
4071 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4072
Yun Park6c86a662017-10-05 16:09:15 -07004073 ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004074 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304075 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004076 "RM PROD resource delete failed %d", ret);
4077
Yun Park6c86a662017-10-05 16:09:15 -07004078 ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
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 CONS resource delete failed %d", ret);
4082}
4083
tfyu0380a972017-07-13 18:19:37 +08004084#ifdef QCA_CONFIG_SMP
4085static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4086{
4087 return netif_rx_ni(skb);
4088}
4089#else
4090static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4091{
4092 struct iphdr *ip_h;
4093 static atomic_t softirq_mitigation_cntr =
4094 ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH);
4095 int result;
4096
4097 ip_h = (struct iphdr *)(skb->data);
4098 if ((skb->protocol == htons(ETH_P_IP)) &&
4099 (ip_h->protocol == IPPROTO_ICMP)) {
4100 result = netif_rx_ni(skb);
4101 } else {
4102 /* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets
4103 * to avoid excessive softirq's.
4104 */
4105 if (atomic_dec_and_test(&softirq_mitigation_cntr)) {
4106 result = netif_rx_ni(skb);
4107 atomic_set(&softirq_mitigation_cntr,
4108 IPA_WLAN_RX_SOFTIRQ_THRESH);
4109 } else {
4110 result = netif_rx(skb);
4111 }
4112 }
4113
4114 return result;
4115}
4116#endif
4117
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004118/**
4119 * hdd_ipa_send_skb_to_network() - Send skb to kernel
4120 * @skb: network buffer
4121 * @adapter: network adapter
4122 *
4123 * Called when a network buffer is received which should not be routed
4124 * to the IPA module.
4125 *
4126 * Return: None
4127 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304128static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004129 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004130{
tfyu0380a972017-07-13 18:19:37 +08004131 int result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004132 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4133 unsigned int cpu_index;
4134
4135 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Jeff Johnson36e74c42017-09-18 08:15:42 -07004136 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%pK",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004137 adapter);
Yun Park46255682017-10-09 15:56:34 -07004138 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004139 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004140 return;
4141 }
4142
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004143 if (cds_is_driver_unloading()) {
Yun Park46255682017-10-09 15:56:34 -07004144 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004145 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146 return;
4147 }
4148
4149 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
4150 skb->dev = adapter->dev;
4151 skb->protocol = eth_type_trans(skb, skb->dev);
4152 skb->ip_summed = CHECKSUM_NONE;
4153
4154 cpu_index = wlan_hdd_get_cpu();
4155
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004156 ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index];
tfyu0380a972017-07-13 18:19:37 +08004157 result = hdd_ipa_aggregated_rx_ind(skb);
4158 if (result == NET_RX_SUCCESS)
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004159 ++adapter->hdd_stats.tx_rx_stats.rx_delivered[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004160 else
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004161 ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004162
Yun Park46255682017-10-09 15:56:34 -07004163 hdd_ipa->ipa_rx_net_send_count++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004164}
4165
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004166/**
Leo Chang69c39692016-10-12 20:11:12 -07004167 * hdd_ipa_forward() - handle packet forwarding to wlan tx
4168 * @hdd_ipa: pointer to hdd ipa context
4169 * @adapter: network adapter
4170 * @skb: data pointer
4171 *
4172 * if exception packet has set forward bit, copied new packet should be
4173 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
4174 * put into pm queue and tx procedure will be differed
4175 *
4176 * Return: None
4177 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07004178static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004179 struct hdd_adapter *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07004180{
Leo Chang69c39692016-10-12 20:11:12 -07004181 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
4182
Leo Chang69c39692016-10-12 20:11:12 -07004183 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Yun Park01deb2c2017-06-14 15:21:44 -07004184
4185 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
4186 qdf_nbuf_ipa_owned_set(skb);
4187
Yun Park46255682017-10-09 15:56:34 -07004188 /* WLAN subsystem is in suspend, put in queue */
Leo Chang69c39692016-10-12 20:11:12 -07004189 if (hdd_ipa->suspended) {
4190 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Yun Park46255682017-10-09 15:56:34 -07004191 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4192 "Tx in suspend, put in queue");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004193 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
4194 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07004195 pm_tx_cb->exception = true;
4196 pm_tx_cb->adapter = adapter;
4197 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004198 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07004199 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4200 hdd_ipa->stats.num_tx_queued++;
4201 } else {
4202 /* Resume, put packet into WLAN TX */
4203 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004204 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07004205 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07004206 "packet Tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08004207 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07004208 } else {
Yun Parkb187d542016-11-14 18:10:04 -08004209 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07004210 }
4211 }
4212}
4213
4214/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004215 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
4216 * @hdd_ipa: pointer to HDD IPA struct
4217 * @adapter: hdd adapter pointer
4218 * @desc: Firmware descriptor
4219 * @skb: Data buffer
4220 *
4221 * Return:
4222 * HDD_IPA_FORWARD_PKT_NONE
4223 * HDD_IPA_FORWARD_PKT_DISCARD
4224 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
4225 *
4226 */
4227
4228static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
4229 struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004230 struct hdd_adapter *adapter,
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004231 uint8_t desc,
4232 qdf_nbuf_t skb)
4233{
4234 int ret = HDD_IPA_FORWARD_PKT_NONE;
Yun Park0dad1002017-07-14 14:57:01 -07004235 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
4236 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004237
4238 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304239 if (!ol_txrx_fwd_desc_thresh_check(
Yun Park0dad1002017-07-14 14:57:01 -07004240 (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc,
4241 (struct cdp_pdev *)pdev,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004242 adapter->session_id))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304243 /* Drop the packet*/
4244 hdd_ipa->stats.num_tx_fwd_err++;
4245 kfree_skb(skb);
4246 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4247 return ret;
4248 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004249 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
4250 "Forward packet to Tx (fw_desc=%d)", desc);
4251 hdd_ipa->ipa_tx_forward++;
4252
4253 if ((desc & FW_RX_DESC_DISCARD_M)) {
4254 hdd_ipa_forward(hdd_ipa, adapter, skb);
Yun Park46255682017-10-09 15:56:34 -07004255 hdd_ipa->ipa_rx_internal_drop_count++;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004256 hdd_ipa->ipa_rx_discard++;
4257 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4258 } else {
4259 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004260
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004261 if (cloned_skb)
4262 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
4263 else
4264 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07004265 "tx skb alloc failed");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004266 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
4267 }
4268 }
4269
4270 return ret;
4271}
4272
4273/**
Yun Park637d6482016-10-05 10:51:33 -07004274 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004275 * @priv: pointer to private data registered with IPA (we register a
4276 * pointer to the global IPA context)
4277 * @evt: the IPA event which triggered the callback
4278 * @data: data associated with the event
4279 *
4280 * Return: None
4281 */
Yun Park6c86a662017-10-05 16:09:15 -07004282static void __hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
4283 unsigned long data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004284{
4285 struct hdd_ipa_priv *hdd_ipa = NULL;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004286 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304287 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004288 uint8_t iface_id;
4289 uint8_t session_id;
4290 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004291 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07004292 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293
4294 hdd_ipa = (struct hdd_ipa_priv *)priv;
4295
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08004296 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
4297 return;
4298
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004299 switch (evt) {
4300 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05304301 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07004302
4303 /*
4304 * When SSR is going on or driver is unloading,
4305 * just drop the packets.
4306 */
4307 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4308 if (0 != status) {
4309 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4310 "Invalid context: drop packet");
Yun Park46255682017-10-09 15:56:34 -07004311 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004312 kfree_skb(skb);
4313 return;
4314 }
4315
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004316 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4317 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004318 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004319 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004320 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4321 session_id, iface_id);
4322 } else {
4323 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4324 }
4325
4326 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304327 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004328 "IPA_RECEIVE: Invalid iface_id: %u",
4329 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004330 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004331 "w2i -- skb",
4332 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Yun Park46255682017-10-09 15:56:34 -07004333 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004334 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004335 return;
4336 }
4337
4338 iface_context = &hdd_ipa->iface_context[iface_id];
4339 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08004340 if (!adapter) {
4341 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4342 "IPA_RECEIVE: Adapter is NULL");
Yun Park46255682017-10-09 15:56:34 -07004343 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Park16a78262017-02-01 12:15:03 -08004344 kfree_skb(skb);
4345 return;
4346 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004347
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304348 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004349 "w2i -- skb",
4350 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004351 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4352 hdd_ipa->stats.num_rx_excep++;
4353 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4354 } else {
4355 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4356 }
4357
4358 iface_context->stats.num_rx_ipa_excep++;
4359
4360 /* Disable to forward Intra-BSS Rx packets when
4361 * ap_isolate=1 in hostapd.conf
4362 */
Jeff Johnsonb9424862017-10-30 08:49:35 -07004363 if (!adapter->session.ap.disable_intrabss_fwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004364 /*
4365 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4366 * all Rx packets to IPA uC, which need to be forwarded
4367 * to other interface.
4368 * And, IPA driver will send back to WLAN host driver
4369 * through exception pipe with fw_desc field set by FW.
4370 * Here we are checking fw_desc field for FORWARD bit
4371 * set, and forward to Tx. Then copy to kernel stack
4372 * only when DISCARD bit is not set.
4373 */
4374 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004375 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4376 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4377 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004378 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004379 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004380 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004381 "Intra-BSS FWD is disabled-skip forward to Tx");
4382 }
4383
4384 hdd_ipa_send_skb_to_network(skb, adapter);
4385 break;
4386
4387 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304388 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004389 "w2i cb wrong event: 0x%x", evt);
4390 return;
4391 }
4392}
4393
4394/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004395 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4396 * @priv: pointer to private data registered with IPA (we register a
4397 * pointer to the global IPA context)
4398 * @evt: the IPA event which triggered the callback
4399 * @data: data associated with the event
4400 *
4401 * Return: None
4402 */
Yun Park6c86a662017-10-05 16:09:15 -07004403static void hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Yun Parkf8d6a122016-10-11 15:49:43 -07004404 unsigned long data)
4405{
4406 cds_ssr_protect(__func__);
4407 __hdd_ipa_w2i_cb(priv, evt, data);
4408 cds_ssr_unprotect(__func__);
4409}
4410
4411/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004412 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4413 * @skb: packet buffer which was transmitted
4414 *
4415 * Return: None
4416 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304417void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004418{
4419 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07004420 qdf_ipa_rx_data_t *ipa_tx_desc;
Yun Park52b2b992016-09-22 15:49:51 -07004421 struct hdd_ipa_tx_desc *tx_desc;
4422 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004423
Yun Park52b2b992016-09-22 15:49:51 -07004424 if (!qdf_nbuf_ipa_owned_get(skb)) {
4425 dev_kfree_skb_any(skb);
4426 return;
4427 }
4428
4429 /* Get Tx desc pointer from SKB CB */
4430 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4431 tx_desc = hdd_ipa->tx_desc_list + id;
4432 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4433
4434 /* Return Tx Desc to IPA */
4435 ipa_free_skb(ipa_tx_desc);
4436
4437 /* Return to free tx desc list */
4438 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4439 tx_desc->ipa_tx_desc_ptr = NULL;
4440 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4441 hdd_ipa->stats.num_tx_desc_q_cnt--;
4442 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443
4444 hdd_ipa->stats.num_tx_comp_cnt++;
4445
4446 atomic_dec(&hdd_ipa->tx_ref_cnt);
4447
4448 hdd_ipa_rm_try_release(hdd_ipa);
4449}
4450
4451/**
4452 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4453 * @iface_context: interface-specific IPA context
4454 * @ipa_tx_desc: packet data descriptor
4455 *
4456 * Return: None
4457 */
4458static void hdd_ipa_send_pkt_to_tl(
4459 struct hdd_ipa_iface_context *iface_context,
Yun Park6c86a662017-10-05 16:09:15 -07004460 qdf_ipa_rx_data_t *ipa_tx_desc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004461{
4462 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004463 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304464 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004465 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004466
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304467 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468 adapter = iface_context->adapter;
4469 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304470 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471 ipa_free_skb(ipa_tx_desc);
4472 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304473 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004474 hdd_ipa_rm_try_release(hdd_ipa);
4475 return;
4476 }
4477
4478 /*
4479 * During CAC period, data packets shouldn't be sent over the air so
4480 * drop all the packets here
4481 */
hqu70708ab2017-10-10 17:52:01 +08004482 if (QDF_SAP_MODE == adapter->device_mode ||
4483 QDF_P2P_GO_MODE == adapter->device_mode) {
4484 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4485 ipa_free_skb(ipa_tx_desc);
4486 qdf_spin_unlock_bh(&iface_context->interface_lock);
4487 iface_context->stats.num_tx_cac_drop++;
4488 hdd_ipa_rm_try_release(hdd_ipa);
4489 return;
4490 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004491 }
4492
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004493 ++adapter->stats.tx_packets;
4494
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304495 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004496
Yun Park6c86a662017-10-05 16:09:15 -07004497 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304499 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004500
4501 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304502 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004503 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304504 qdf_nbuf_mapped_paddr_set(skb,
Yun Park6c86a662017-10-05 16:09:15 -07004505 QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc)
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004506 + HDD_IPA_WLAN_FRAG_HEADER
4507 + HDD_IPA_WLAN_IPA_HEADER);
Yun Park6c86a662017-10-05 16:09:15 -07004508 QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004509 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4510 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304511 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512
Yun Park52b2b992016-09-22 15:49:51 -07004513 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4514 /* get free Tx desc and assign ipa_tx_desc pointer */
4515 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4516 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4517 struct hdd_ipa_tx_desc, link);
4518 list_del(&tx_desc->link);
4519 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4520 hdd_ipa->stats.num_tx_desc_q_cnt++;
4521 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4522 /* Store Tx Desc index into SKB CB */
4523 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4524 } else {
4525 hdd_ipa->stats.num_tx_desc_error++;
4526 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Yun Park52b2b992016-09-22 15:49:51 -07004527 ipa_free_skb(ipa_tx_desc);
4528 hdd_ipa_rm_try_release(hdd_ipa);
4529 return;
4530 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004531
Yun Park6c86a662017-10-05 16:09:15 -07004532 adapter->stats.tx_bytes += QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004533
Leo Changfdb45c32016-10-28 11:09:23 -07004534 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Yun Park6c86a662017-10-05 16:09:15 -07004535 (struct cdp_vdev *)iface_context->tl_context,
4536 QDF_IPA_RX_DATA_SKB(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004537 if (skb) {
jiad05c1e812017-08-01 16:48:52 +08004538 qdf_nbuf_free(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004539 iface_context->stats.num_tx_err++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004540 return;
4541 }
4542
4543 atomic_inc(&hdd_ipa->tx_ref_cnt);
4544
4545 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004546}
4547
4548/**
Leo Chang11545d62016-10-17 14:53:50 -07004549 * hdd_ipa_is_present() - get IPA hw status
4550 * @hdd_ctx: pointer to hdd context
4551 *
4552 * ipa_uc_reg_rdyCB is not directly designed to check
4553 * ipa hw status. This is an undocumented function which
4554 * has confirmed with IPA team.
4555 *
4556 * Return: true - ipa hw present
4557 * false - ipa hw not present
4558 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004559bool hdd_ipa_is_present(struct hdd_context *hdd_ctx)
Leo Chang11545d62016-10-17 14:53:50 -07004560{
4561 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004562 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004563 return true;
4564 else
4565 return false;
4566}
4567
4568/**
Leo Chang69c39692016-10-12 20:11:12 -07004569 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004570 * @work: pointer to the scheduled work
4571 *
4572 * Called during PM resume to send packets to TL which were queued
4573 * while host was in the process of suspending.
4574 *
4575 * Return: None
4576 */
Leo Chang69c39692016-10-12 20:11:12 -07004577static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004578{
4579 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4580 struct hdd_ipa_priv,
4581 pm_work);
4582 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304583 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004584 uint32_t dequeued = 0;
4585
Leo Chang69c39692016-10-12 20:11:12 -07004586 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4587 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304588 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304589 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4590 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304591 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004592
4593 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004595 if (pm_tx_cb->exception) {
Yun Park46255682017-10-09 15:56:34 -07004596 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4597 "Flush Exception");
Govind Singh1dab23b2017-08-12 13:31:00 +05304598 if (pm_tx_cb->adapter->dev)
4599 hdd_softap_hard_start_xmit(skb,
4600 pm_tx_cb->adapter->dev);
Govind Singh02075942017-08-15 11:13:28 +05304601 else
4602 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004603 } else {
4604 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004605 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004606 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304607 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004608 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304609 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004610 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4611 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004612
4613 hdd_ipa->stats.num_tx_dequeued += dequeued;
4614 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4615 hdd_ipa->stats.num_max_pm_queue = dequeued;
4616}
4617
4618/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004619 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004620 * @priv: pointer to private data registered with IPA (we register a
4621 * pointer to the interface-specific IPA context)
4622 * @evt: the IPA event which triggered the callback
4623 * @data: data associated with the event
4624 *
4625 * Return: None
4626 */
Yun Park6c86a662017-10-05 16:09:15 -07004627static void __hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
4628 unsigned long data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004629{
4630 struct hdd_ipa_priv *hdd_ipa = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07004631 qdf_ipa_rx_data_t *ipa_tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004632 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304633 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004634 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304635 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004636
Mukul Sharma81661ae2015-10-30 20:26:02 +05304637 iface_context = (struct hdd_ipa_iface_context *)priv;
Yun Park6c86a662017-10-05 16:09:15 -07004638 ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004639 hdd_ipa = iface_context->hdd_ipa;
4640
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004641 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004642 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4643 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644 iface_context->stats.num_tx_drop++;
4645 return;
4646 }
4647
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004648 /*
4649 * When SSR is going on or driver is unloading, just drop the packets.
4650 * During SSR, there is no use in queueing the packets as STA has to
4651 * connect back any way
4652 */
4653 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304654 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004655 ipa_free_skb(ipa_tx_desc);
4656 iface_context->stats.num_tx_drop++;
4657 return;
4658 }
4659
Yun Park6c86a662017-10-05 16:09:15 -07004660 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004661
Yun Parkb187d542016-11-14 18:10:04 -08004662 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4663 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004664
4665 /*
4666 * If PROD resource is not requested here then there may be cases where
4667 * IPA hardware may be clocked down because of not having proper
4668 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4669 * workaround to request PROD resource while data is going over CONS
4670 * pipe to prevent the IPA hardware clockdown.
4671 */
4672 hdd_ipa_rm_request(hdd_ipa);
4673
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304674 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004675 /*
4676 * If host is still suspended then queue the packets and these will be
4677 * drained later when resume completes. When packet is arrived here and
4678 * host is suspended, this means that there is already resume is in
4679 * progress.
4680 */
4681 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304682 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004683 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4684 pm_tx_cb->iface_context = iface_context;
4685 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304686 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004687 hdd_ipa->stats.num_tx_queued++;
4688
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304689 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004690 return;
4691 }
4692
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304693 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004694
4695 /*
4696 * If we are here means, host is not suspended, wait for the work queue
4697 * to finish.
4698 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004699 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004700
4701 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4702}
4703
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004704/*
4705 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4706 * @priv: pointer to private data registered with IPA (we register a
4707 * pointer to the interface-specific IPA context)
4708 * @evt: the IPA event which triggered the callback
4709 * @data: data associated with the event
4710 *
4711 * Return: None
4712 */
Yun Park6c86a662017-10-05 16:09:15 -07004713static void hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004714 unsigned long data)
4715{
4716 cds_ssr_protect(__func__);
4717 __hdd_ipa_i2w_cb(priv, evt, data);
4718 cds_ssr_unprotect(__func__);
4719}
4720
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004721/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004722 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004723 * @hdd_ctx: Global HDD context
4724 *
4725 * Return: 0 on success, negativer errno on error
4726 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004727static int __hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004728{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004729 struct hdd_ipa_priv *hdd_ipa;
4730
4731 if (wlan_hdd_validate_context(hdd_ctx))
4732 return 0;
4733
4734 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004735
4736 if (!hdd_ipa_is_enabled(hdd_ctx))
4737 return 0;
4738
4739 /*
4740 * Check if IPA is ready for suspend, If we are here means, there is
4741 * high chance that suspend would go through but just to avoid any race
4742 * condition after suspend started, these checks are conducted before
4743 * allowing to suspend.
4744 */
4745 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4746 return -EAGAIN;
4747
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304748 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004749
4750 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304751 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004752 return -EAGAIN;
4753 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304754 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004755
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304756 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004757 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304758 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004759
4760 return 0;
4761}
4762
4763/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004764 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4765 * @hdd_ctx: Global HDD context
4766 *
4767 * Return: 0 on success, negativer errno on error
4768 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004769int hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004770{
4771 int ret;
4772
4773 cds_ssr_protect(__func__);
4774 ret = __hdd_ipa_suspend(hdd_ctx);
4775 cds_ssr_unprotect(__func__);
4776
4777 return ret;
4778}
4779
4780/**
4781 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004782 * hdd_ctx: Global HDD context
4783 *
4784 * Return: 0 on success, negative errno on error
4785 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004786static int __hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004787{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004788 struct hdd_ipa_priv *hdd_ipa;
4789
4790 if (wlan_hdd_validate_context(hdd_ctx))
4791 return 0;
4792
4793 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004794
4795 if (!hdd_ipa_is_enabled(hdd_ctx))
4796 return 0;
4797
4798 schedule_work(&hdd_ipa->pm_work);
4799
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304800 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004801 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304802 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004803
4804 return 0;
4805}
4806
4807/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004808 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4809 * hdd_ctx: Global HDD context
4810 *
4811 * Return: 0 on success, negative errno on error
4812 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004813int hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004814{
4815 int ret;
4816
4817 cds_ssr_protect(__func__);
4818 ret = __hdd_ipa_resume(hdd_ctx);
4819 cds_ssr_unprotect(__func__);
4820
4821 return ret;
4822}
4823
4824/**
Yun Park52b2b992016-09-22 15:49:51 -07004825 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
4826 * @hdd_ipa: Global HDD IPA context
4827 *
4828 * Return: 0 on success, negative errno on error
4829 */
4830static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
4831{
4832 int i;
4833 uint32_t max_desc_cnt;
4834 struct hdd_ipa_tx_desc *tmp_desc;
4835
Yun Parkd9c528e2017-08-30 16:34:57 -07004836 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
Yun Park52b2b992016-09-22 15:49:51 -07004837
4838 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
4839
jiad14fe4fb2017-08-08 13:33:14 +08004840 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc) *
Yun Parkd9c528e2017-08-30 16:34:57 -07004841 max_desc_cnt);
Yun Park52b2b992016-09-22 15:49:51 -07004842
4843 if (!tmp_desc) {
4844 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkd9c528e2017-08-30 16:34:57 -07004845 "Free Tx descriptor allocation failed");
Yun Park52b2b992016-09-22 15:49:51 -07004846 return -ENOMEM;
4847 }
4848
4849 hdd_ipa->tx_desc_list = tmp_desc;
4850
4851 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07004852 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07004853 tmp_desc->id = i;
4854 tmp_desc->ipa_tx_desc_ptr = NULL;
4855 list_add_tail(&tmp_desc->link,
4856 &hdd_ipa->free_tx_desc_head);
4857 tmp_desc++;
4858 }
4859
4860 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4861 hdd_ipa->stats.num_tx_desc_error = 0;
4862
4863 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4864
4865 return 0;
4866}
4867
Yun Park9281cb72017-11-30 11:14:30 -08004868#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Yun Park52b2b992016-09-22 15:49:51 -07004869/**
Yun Park9281cb72017-11-30 11:14:30 -08004870 * hdd_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004871 * @hdd_ipa: Global HDD IPA context
Yun Park9281cb72017-11-30 11:14:30 -08004872 * @desc_fifo_sz: Number of descriptors
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004873 *
4874 * Return: 0 on success, negative errno on error
4875 */
Yun Park9281cb72017-11-30 11:14:30 -08004876static int hdd_ipa_setup_tx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
4877 int32_t desc_fifo_sz)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004878{
4879 int i, ret = 0;
Yun Park6c86a662017-10-05 16:09:15 -07004880 qdf_ipa_sys_connect_params_t *ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004881
4882 /*setup TX pipes */
4883 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4884 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4885
4886 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4887 ipa->desc_fifo_sz = desc_fifo_sz;
4888 ipa->priv = &hdd_ipa->iface_context[i];
4889 ipa->notify = hdd_ipa_i2w_cb;
4890
4891 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4892 ipa->ipa_ep_cfg.hdr.hdr_len =
4893 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4894 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4895 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4896 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4897 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4898 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4899 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4900 } else {
4901 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4902 }
4903 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4904
4905 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4906 ipa->keep_ipa_awake = 1;
4907
Yun Park6c86a662017-10-05 16:09:15 -07004908 ret = qdf_ipa_setup_sys_pipe(ipa,
4909 &hdd_ipa->sys_pipe[i].conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004910 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004911 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4912 "Failed for pipe %d ret: %d", i, ret);
Yun Park9281cb72017-11-30 11:14:30 -08004913 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004914 }
4915 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4916 }
4917
Yun Park9281cb72017-11-30 11:14:30 -08004918 return ret;
4919}
4920#else
4921/**
4922 * hdd_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
4923 * @hdd_ipa: Global HDD IPA context
4924 * @desc_fifo_sz: Number of descriptors
4925 *
4926 * Return: 0 on success, negative errno on error
4927 */
4928static int hdd_ipa_setup_tx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
4929 int32_t desc_fifo_sz)
4930{
4931 /*
4932 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
4933 * is enabled, where per vdev descriptors are supported in firmware.
4934 */
4935 return 0;
4936}
4937#endif
4938
4939/**
4940 * hdd_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
4941 * @hdd_ipa: Global HDD IPA context
4942 * @desc_fifo_sz: Number of descriptors
4943 *
4944 * Return: 0 on success, negative errno on error
4945 */
4946static int hdd_ipa_setup_rx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
4947 int32_t desc_fifo_sz)
4948{
4949 int ret = 0;
4950 qdf_ipa_sys_connect_params_t *ipa;
4951
4952 /*
4953 * Hard code it here, this can be extended if in case
4954 * PROD pipe is also per interface.
4955 * Right now there is no advantage of doing this.
4956 */
4957 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4958
4959 ipa->client = IPA_CLIENT_WLAN1_PROD;
4960
4961 ipa->desc_fifo_sz = desc_fifo_sz;
4962 ipa->priv = hdd_ipa;
4963 ipa->notify = hdd_ipa_w2i_cb;
4964
4965 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4966 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4967 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4968 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4969
4970 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4971 ipa->keep_ipa_awake = 1;
4972
4973 ret = qdf_ipa_setup_sys_pipe(ipa,
4974 &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl);
4975 if (ret) {
4976 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4977 "Failed for RX pipe: %d", ret);
4978 return ret;
4979 }
4980 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4981
4982 return ret;
4983}
4984
4985/**
4986 * hdd_ipa_setup_sys_pipe() - Setup all IPA system pipes
4987 * @hdd_ipa: Global HDD IPA context
4988 *
4989 * Return: 0 on success, negative errno on error
4990 */
4991static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4992{
4993 int i = HDD_IPA_MAX_IFACE, ret = 0;
4994 uint32_t desc_fifo_sz;
4995
4996 /* The maximum number of descriptors that can be provided to a BAM at
4997 * once is one less than the total number of descriptors that the buffer
4998 * can contain.
4999 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
5000 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
5001 * be provided at once.
5002 * Because of above requirement, one extra descriptor will be added to
5003 * make sure hardware always has one descriptor.
5004 */
5005 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
Yuanyuan Liu23a8eec2017-12-15 16:01:12 -08005006 + SPS_DESC_SIZE;
Yun Park9281cb72017-11-30 11:14:30 -08005007
5008 ret = hdd_ipa_setup_tx_sys_pipe(hdd_ipa, desc_fifo_sz);
5009 if (ret) {
5010 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5011 "Failed for TX pipe: %d", ret);
5012 goto setup_sys_pipe_fail;
5013 }
5014
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005015 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park9281cb72017-11-30 11:14:30 -08005016 ret = hdd_ipa_setup_rx_sys_pipe(hdd_ipa, desc_fifo_sz);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005017 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305018 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park9281cb72017-11-30 11:14:30 -08005019 "Failed for RX pipe: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005020 goto setup_sys_pipe_fail;
5021 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005022 }
5023
Yun Parkd9c528e2017-08-30 16:34:57 -07005024 /* Allocate free Tx desc list */
Yun Park52b2b992016-09-22 15:49:51 -07005025 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
5026 if (ret)
5027 goto setup_sys_pipe_fail;
5028
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005029 return ret;
5030
5031setup_sys_pipe_fail:
5032
Yun Park9281cb72017-11-30 11:14:30 -08005033 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
5034 if (hdd_ipa->sys_pipe[i].conn_hdl_valid)
5035 qdf_ipa_teardown_sys_pipe(
5036 hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305037 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005038 sizeof(struct hdd_ipa_sys_pipe));
5039 }
5040
5041 return ret;
5042}
5043
5044/**
5045 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
5046 * @hdd_ipa: Global HDD IPA context
5047 *
5048 * Return: None
5049 */
5050static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
5051{
5052 int ret = 0, i;
Yun Parkd9c528e2017-08-30 16:34:57 -07005053 uint32_t max_desc_cnt;
Yun Park52b2b992016-09-22 15:49:51 -07005054 struct hdd_ipa_tx_desc *tmp_desc;
Yun Park6c86a662017-10-05 16:09:15 -07005055 qdf_ipa_rx_data_t *ipa_tx_desc;
Yun Park52b2b992016-09-22 15:49:51 -07005056
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005057 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
5058 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
Yun Park9281cb72017-11-30 11:14:30 -08005059 ret = qdf_ipa_teardown_sys_pipe(
5060 hdd_ipa->sys_pipe[i].conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005061 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305062 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005063 ret);
5064
5065 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
5066 }
5067 }
Yun Park52b2b992016-09-22 15:49:51 -07005068
5069 if (hdd_ipa->tx_desc_list) {
Yun Parkd9c528e2017-08-30 16:34:57 -07005070 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
5071
Yun Park52b2b992016-09-22 15:49:51 -07005072 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07005073 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07005074 tmp_desc = hdd_ipa->tx_desc_list + i;
5075 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
5076 if (ipa_tx_desc)
5077 ipa_free_skb(ipa_tx_desc);
5078 }
5079 tmp_desc = hdd_ipa->tx_desc_list;
5080 hdd_ipa->tx_desc_list = NULL;
5081 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
5082 hdd_ipa->stats.num_tx_desc_error = 0;
5083 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
5084 qdf_mem_free(tmp_desc);
5085 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005086}
5087
5088/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005089 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
5090 * @iface_context: interface-specific IPA context
5091 *
5092 * Return: None
5093 */
5094static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
5095{
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005096 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07005097
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005098 if (iface_context == NULL)
5099 return;
Orhan K AKYILDIZ3332be32017-05-31 15:36:31 -07005100 if (iface_context->adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
5101 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
5102 "%s: bad adapter(%pK).magic(%d)!",
5103 __func__, iface_context->adapter,
5104 iface_context->adapter->magic);
5105 return;
5106 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005107
Yun Parkb4f591d2017-03-29 15:51:01 -07005108 cdp_ipa_cleanup_iface(cds_get_context(QDF_MODULE_ID_SOC),
5109 iface_context->adapter->dev->name,
5110 hdd_ipa_is_ipv6_enabled(iface_context->hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005111
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305112 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005113 iface_context->adapter->ipa_context = NULL;
5114 iface_context->adapter = NULL;
5115 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305116 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005117 iface_context->ifa_address = 0;
5118 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305119 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005120 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05305121 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005122 }
5123 iface_context->hdd_ipa->num_iface--;
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005124 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005125 iface_context->hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005126}
5127
5128/**
5129 * hdd_ipa_setup_iface() - Setup IPA on a given interface
5130 * @hdd_ipa: HDD IPA global context
5131 * @adapter: Interface upon which IPA is being setup
5132 * @sta_id: Station ID of the API instance
5133 *
5134 * Return: 0 on success, negative errno value on error
5135 */
5136static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07005137 struct hdd_adapter *adapter, uint8_t sta_id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005138{
5139 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park0dad1002017-07-14 14:57:01 -07005140 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
5141 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005142 void *tl_context = NULL;
5143 int i, ret = 0;
5144
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005145 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07005146
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005147 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
5148 * channel change indication. Since these indications are sent by lower
5149 * layer as SAP updates and IPA doesn't have to do anything for these
5150 * updates so ignoring!
5151 */
Krunal Sonibe766b02016-03-10 13:00:44 -08005152 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005153 return 0;
5154
5155 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5156 if (hdd_ipa->iface_context[i].adapter == NULL) {
5157 iface_context = &(hdd_ipa->iface_context[i]);
5158 break;
5159 }
5160 }
5161
5162 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305163 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005164 "All the IPA interfaces are in use");
5165 ret = -ENOMEM;
5166 goto end;
5167 }
5168
5169 adapter->ipa_context = iface_context;
5170 iface_context->adapter = adapter;
5171 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08005172 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Yun Park0dad1002017-07-14 14:57:01 -07005173 soc, (struct cdp_pdev *)pdev, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005174 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305175 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005176 "Not able to get TL context sta_id: %d", sta_id);
5177 ret = -EINVAL;
5178 goto end;
5179 }
5180
5181 iface_context->tl_context = tl_context;
5182
Yun Parkb4f591d2017-03-29 15:51:01 -07005183 ret = cdp_ipa_setup_iface(cds_get_context(QDF_MODULE_ID_SOC),
5184 adapter->dev->name, adapter->dev->dev_addr,
5185 iface_context->prod_client,
5186 iface_context->cons_client,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005187 adapter->session_id,
Yun Parkb4f591d2017-03-29 15:51:01 -07005188 hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005189 if (ret)
5190 goto end;
5191
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005192 hdd_ipa->num_iface++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005193
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005194 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005195 hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005196 return ret;
5197
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005198end:
5199 if (iface_context)
5200 hdd_ipa_cleanup_iface(iface_context);
5201 return ret;
5202}
5203
Yun Parka27049a2016-10-11 12:30:49 -07005204#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005205/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005206 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Jeff Johnson4929cd92017-10-06 19:21:57 -07005207 * @hdd_ctx: HDD context
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005208 * @mcc_mode: 0=MCC/1=SCC
5209 *
5210 * Return: 0 on success, negative errno value on error
5211 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07005212static int __hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx,
5213 bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005214{
Jeff Johnson089d0432017-10-02 13:27:21 -07005215 struct hdd_adapter *adapter;
Yun Park6c86a662017-10-05 16:09:15 -07005216 qdf_ipa_msg_meta_t meta;
5217 qdf_ipa_wlan_msg_t *msg;
5218
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005219 int ret;
5220
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005221 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005222 return -EINVAL;
5223
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005224 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
5225 return -EINVAL;
5226
5227 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005228 /* Flush TxRx queue for each adapter before switch to SCC */
Dustin Brown920397d2017-12-13 16:27:50 -08005229 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson089d0432017-10-02 13:27:21 -07005230 if (adapter->device_mode == QDF_STA_MODE ||
5231 adapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005232 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnson089d0432017-10-02 13:27:21 -07005233 adapter->device_mode);
5234 hdd_deinit_tx_rx(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005235 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005236 }
5237 }
5238
5239 /* Send SCC/MCC Switching event to IPA */
Yun Park6c86a662017-10-05 16:09:15 -07005240 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
5241 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005242 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005243 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005244 return -ENOMEM;
5245 }
5246
Yun Park6c86a662017-10-05 16:09:15 -07005247 QDF_IPA_MSG_META_MSG_TYPE(&meta) = mcc_mode ?
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005248 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Yun Park6c86a662017-10-05 16:09:15 -07005249 hdd_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005250
Yun Park6c86a662017-10-05 16:09:15 -07005251 ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005252
5253 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005254 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Yun Park6c86a662017-10-05 16:09:15 -07005255 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305256 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005257 }
5258
5259 return ret;
5260}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005261
5262/**
5263 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5264 * @mcc_mode: 0=MCC/1=SCC
5265 *
5266 * Return: 0 on success, negative errno value on error
5267 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005268int hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx, bool mcc_mode)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005269{
5270 int ret;
5271
5272 cds_ssr_protect(__func__);
5273 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5274 cds_ssr_unprotect(__func__);
5275
5276 return ret;
5277}
Yun Parka27049a2016-10-11 12:30:49 -07005278#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005279
5280/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005281 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5282 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5283 *
Yun Park6c86a662017-10-05 16:09:15 -07005284 * Return: qdf_ipa_wlan_event representing the hdd_ipa_wlan_event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005285 */
Yun Park6c86a662017-10-05 16:09:15 -07005286static qdf_ipa_wlan_event_t
Mohit Khannafa99aea2016-05-12 21:43:13 -07005287hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5288{
Yun Park6c86a662017-10-05 16:09:15 -07005289 qdf_ipa_wlan_event_t ipa_event;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005290
5291 switch (hdd_ipa_event_type) {
5292 case HDD_IPA_CLIENT_CONNECT:
5293 ipa_event = WLAN_CLIENT_CONNECT;
5294 break;
5295 case HDD_IPA_CLIENT_DISCONNECT:
5296 ipa_event = WLAN_CLIENT_DISCONNECT;
5297 break;
5298 case HDD_IPA_AP_CONNECT:
5299 ipa_event = WLAN_AP_CONNECT;
5300 break;
5301 case HDD_IPA_AP_DISCONNECT:
5302 ipa_event = WLAN_AP_DISCONNECT;
5303 break;
5304 case HDD_IPA_STA_CONNECT:
5305 ipa_event = WLAN_STA_CONNECT;
5306 break;
5307 case HDD_IPA_STA_DISCONNECT:
5308 ipa_event = WLAN_STA_DISCONNECT;
5309 break;
5310 case HDD_IPA_CLIENT_CONNECT_EX:
5311 ipa_event = WLAN_CLIENT_CONNECT_EX;
5312 break;
5313 case HDD_IPA_WLAN_EVENT_MAX:
5314 default:
5315 ipa_event = IPA_WLAN_EVENT_MAX;
5316 break;
5317 }
5318 return ipa_event;
5319
5320}
5321
5322/**
5323 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005324 * @adapter: adapter upon which the event was received
5325 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005326 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005327 * @mac_address: MAC address associated with the event
5328 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005329 * This function is meant to be called from within wlan_hdd_ipa.c
5330 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005331 * Return: 0 on success, negative errno value on error
5332 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005333static int __hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Yun Park6c86a662017-10-05 16:09:15 -07005334 qdf_ipa_wlan_event_t type, uint8_t *mac_addr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005335{
5336 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07005337 qdf_ipa_msg_meta_t meta;
5338 qdf_ipa_wlan_msg_t *msg;
5339 qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005340 int ret;
5341
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005342 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: EVT: %s, MAC: %pM, sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005343 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5344 mac_addr, sta_id);
5345
5346 if (type >= IPA_WLAN_EVENT_MAX)
5347 return -EINVAL;
5348
5349 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5350 return -EINVAL;
5351
5352 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305353 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005354 return -EINVAL;
5355 }
5356
5357 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5358 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005359 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005360 return 0;
5361 }
5362
5363 /*
5364 * During IPA UC resource loading/unloading new events can be issued.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005365 */
Yun Park777d7242017-03-30 15:38:33 -07005366 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5367 (hdd_ipa->resource_loading || hdd_ipa->resource_unloading)) {
5368 unsigned int pending_event_count;
5369 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005370
Yun Park46255682017-10-09 15:56:34 -07005371 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park777d7242017-03-30 15:38:33 -07005372 "%s:IPA resource %s inprogress",
5373 hdd_ipa_wlan_event_to_str(type),
5374 hdd_ipa->resource_loading ?
5375 "load" : "unload");
5376
5377 /* Wait until completion of the long/unloading */
5378 ret = wait_for_completion_timeout(&hdd_ipa->ipa_resource_comp,
5379 msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME));
5380 if (!ret) {
5381 /*
5382 * If timed out, store the events separately and
5383 * handle them later.
5384 */
Yun Park46255682017-10-09 15:56:34 -07005385 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park777d7242017-03-30 15:38:33 -07005386 "IPA resource %s timed out",
5387 hdd_ipa->resource_loading ?
5388 "load" : "unload");
Yun Park7c4f31b2016-11-30 10:09:21 -08005389
Yun Parka4bb37c2017-12-08 16:14:22 -08005390 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005391
Yun Parka4bb37c2017-12-08 16:14:22 -08005392 pending_event_count =
5393 qdf_list_size(&hdd_ipa->pending_event);
5394 if (pending_event_count >=
5395 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
5396 hdd_debug("Reached max pending event count");
5397 qdf_list_remove_front(
5398 &hdd_ipa->pending_event,
5399 (qdf_list_node_t **)&pending_event);
5400 } else {
5401 pending_event =
5402 (struct ipa_uc_pending_event *)
5403 qdf_mem_malloc(sizeof(
Yun Park777d7242017-03-30 15:38:33 -07005404 struct ipa_uc_pending_event));
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005405 }
Yun Parka4bb37c2017-12-08 16:14:22 -08005406
5407 if (!pending_event) {
5408 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5409 "Pending event memory alloc fail");
5410 qdf_mutex_release(&hdd_ipa->ipa_lock);
5411 return -ENOMEM;
5412 }
5413
5414 pending_event->adapter = adapter;
5415 pending_event->sta_id = sta_id;
5416 pending_event->type = type;
5417 pending_event->is_loading =
5418 hdd_ipa->resource_loading;
5419 qdf_mem_copy(pending_event->mac_addr,
5420 mac_addr, QDF_MAC_ADDR_SIZE);
5421 qdf_list_insert_back(&hdd_ipa->pending_event,
5422 &pending_event->node);
5423
5424 qdf_mutex_release(&hdd_ipa->ipa_lock);
5425
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005426 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005427 }
Yun Park46255682017-10-09 15:56:34 -07005428 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Jeff Johnson4929cd92017-10-06 19:21:57 -07005429 "IPA resource %s completed",
5430 hdd_ipa->resource_loading ?
5431 "load" : "unload");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005432 }
5433
5434 hdd_ipa->stats.event[type]++;
5435
Yun Park6c86a662017-10-05 16:09:15 -07005436 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005437 switch (type) {
5438 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005439 qdf_mutex_acquire(&hdd_ipa->event_lock);
5440
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005441 /* STA already connected and without disconnect, connect again
5442 * This is Roaming scenario
5443 */
5444 if (hdd_ipa->sta_connected)
5445 hdd_ipa_cleanup_iface(adapter->ipa_context);
5446
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005447 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5448 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305449 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005450 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005451 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005452
Yun Park8f289c82016-10-18 16:38:21 -07005453 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5454 (hdd_ipa->sap_num_connected_sta > 0) &&
5455 !hdd_ipa->sta_connected) {
5456 qdf_mutex_release(&hdd_ipa->event_lock);
5457 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005458 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005459 qdf_mutex_acquire(&hdd_ipa->event_lock);
5460 }
5461
Jeff Johnson1b780e42017-10-31 14:11:45 -07005462 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005463 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005464 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005465
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005466 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005467
5468 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005469
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005470 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005471 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005472 break;
5473
5474 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005475 qdf_mutex_acquire(&hdd_ipa->event_lock);
5476
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005477 /* For DFS channel we get two start_bss event (before and after
5478 * CAC). Also when ACS range includes both DFS and non DFS
5479 * channels, we could possibly change channel many times due to
5480 * RADAR detection and chosen channel may not be a DFS channels.
5481 * So dont return error here. Just discard the event.
5482 */
Yun Park8f289c82016-10-18 16:38:21 -07005483 if (adapter->ipa_context) {
5484 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005485 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005486 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005487
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005488 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5489 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005490 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005491 hdd_err("%s: Evt: %d, Interface setup failed",
Yun Park6c86a662017-10-05 16:09:15 -07005492 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005493 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005494 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005495
Yun Park8f289c82016-10-18 16:38:21 -07005496 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5497 qdf_mutex_release(&hdd_ipa->event_lock);
5498 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005499 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005500 qdf_mutex_acquire(&hdd_ipa->event_lock);
5501 }
5502
Jeff Johnson1b780e42017-10-31 14:11:45 -07005503 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005504 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005505 (adapter->ipa_context))->iface_id;
5506
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305507 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005508 break;
5509
5510 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305511 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005512
5513 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005514 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005515 hdd_err("%s: Evt: %d, STA already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005516 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005517 return -EINVAL;
5518 }
Yun Parka37592b2016-06-11 17:10:28 -07005519
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005520 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005521
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005522 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005523 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005524 msg_ex->name);
5525 } else {
5526 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Park3b7152b2017-08-25 08:33:37 -07005527 if ((1 == hdd_ipa->num_iface) &&
Yun Parka37592b2016-06-11 17:10:28 -07005528 (HDD_IPA_UC_NUM_WDI_PIPE ==
Yun Park3b7152b2017-08-25 08:33:37 -07005529 hdd_ipa->activated_fw_pipe) &&
5530 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005531 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005532 }
5533
Yun Park74127cf2016-09-18 11:22:41 -07005534 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5535 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005536 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005537 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005538 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005539 qdf_mutex_acquire(&hdd_ipa->event_lock);
Jeff Johnson1b780e42017-10-31 14:11:45 -07005540 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005541 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005542 }
5543
Yun Park8f289c82016-10-18 16:38:21 -07005544 hdd_ipa_cleanup_iface(adapter->ipa_context);
5545
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305546 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005547
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005548 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005549 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005550 break;
5551
5552 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005553 qdf_mutex_acquire(&hdd_ipa->event_lock);
5554
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005555 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005556 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005557 hdd_err("%s: Evt: %d, SAP already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005558 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005559 return -EINVAL;
5560 }
5561
Yun Park3b7152b2017-08-25 08:33:37 -07005562 if ((1 == hdd_ipa->num_iface) &&
5563 (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
5564 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005565 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005566 /*
5567 * We disable WDI pipes directly here since
5568 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5569 * processed when unloading WLAN driver is in
5570 * progress
5571 */
5572 hdd_ipa_uc_disable_pipes(hdd_ipa);
5573 } else {
Yun Park199c2ed2017-10-02 11:24:22 -07005574 /*
5575 * This shouldn't happen :
5576 * No interface left but WDI pipes are still
5577 * active - force close WDI pipes
5578 */
5579 WARN_ON(1);
5580 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
5581 "No interface left but WDI pipes are still active - force close WDI pipes");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005582 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5583 }
5584 }
5585
5586 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005587 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005588 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005589 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005590 qdf_mutex_acquire(&hdd_ipa->event_lock);
Jeff Johnson1b780e42017-10-31 14:11:45 -07005591 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005592 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005593 }
Yun Parka37592b2016-06-11 17:10:28 -07005594
Yun Park8f289c82016-10-18 16:38:21 -07005595 hdd_ipa_cleanup_iface(adapter->ipa_context);
5596
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305597 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005598 break;
5599
5600 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005601 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005602 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005603 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305604 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005605 return 0;
5606 }
5607
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305608 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005609 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5610 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005611 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305612 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005613 "%s: STA ID %d found, not valid",
5614 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005615 return 0;
5616 }
Yun Park312f71a2015-12-08 10:22:42 -08005617
5618 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005619 if (hdd_ipa->sap_num_connected_sta == 0 &&
5620 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005621 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005622 hdd_ipa->sta_connected) {
5623 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005624 hdd_ipa_uc_offload_enable_disable(
5625 hdd_get_adapter(hdd_ipa->hdd_ctx,
5626 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005627 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005628 qdf_mutex_acquire(&hdd_ipa->event_lock);
5629 }
Yun Parka37592b2016-06-11 17:10:28 -07005630
Yun Park312f71a2015-12-08 10:22:42 -08005631 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5632 if (ret) {
Yun Park46255682017-10-09 15:56:34 -07005633 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park312f71a2015-12-08 10:22:42 -08005634 "%s: handle 1st con ret %d",
5635 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005636
5637 if (hdd_ipa_uc_sta_is_enabled(
5638 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005639 hdd_ipa->sta_connected) {
5640 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005641 hdd_ipa_uc_offload_enable_disable(
5642 hdd_get_adapter(
5643 hdd_ipa->hdd_ctx,
5644 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005645 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005646 } else {
5647 qdf_mutex_release(&hdd_ipa->event_lock);
5648 }
Yun Parka37592b2016-06-11 17:10:28 -07005649
Yun Park312f71a2015-12-08 10:22:42 -08005650 return ret;
5651 }
5652 }
5653
5654 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005655
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305656 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005657
Yun Park6c86a662017-10-05 16:09:15 -07005658 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
5659 QDF_IPA_MSG_META_MSG_LEN(&meta) =
5660 (sizeof(qdf_ipa_wlan_msg_ex_t) +
5661 sizeof(qdf_ipa_wlan_hdr_attrib_val_t));
5662 msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005663
5664 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305665 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005666 "msg_ex allocation failed");
5667 return -ENOMEM;
5668 }
5669 strlcpy(msg_ex->name, adapter->dev->name,
5670 IPA_RESOURCE_NAME_MAX);
5671 msg_ex->num_of_attribs = 1;
5672 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5673 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5674 msg_ex->attribs[0].offset =
5675 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5676 } else {
5677 msg_ex->attribs[0].offset =
5678 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5679 }
5680 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5681 IPA_MAC_ADDR_SIZE);
5682
5683 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5684
5685 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005686 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305687 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305688 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005689 return ret;
5690 }
5691 hdd_ipa->stats.num_send_msg++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005692
Yun Park199c2ed2017-10-02 11:24:22 -07005693 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005694 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005695 return ret;
5696
5697 case WLAN_CLIENT_DISCONNECT:
5698 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005699 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005700 "%s: IPA UC OFFLOAD NOT ENABLED",
5701 msg_ex->name);
5702 return 0;
5703 }
5704
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305705 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Park73ea8bb2017-08-25 07:27:39 -07005706 if (!hdd_ipa->sap_num_connected_sta) {
5707 qdf_mutex_release(&hdd_ipa->event_lock);
5708 hdd_err("%s: Evt: %d, Client already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005709 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Yun Park73ea8bb2017-08-25 07:27:39 -07005710 return 0;
5711 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005712 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005713 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305714 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005715 "%s: STA ID %d NOT found, not valid",
5716 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005717 return 0;
5718 }
5719 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005720
Yun Park9b5030f2016-11-08 12:02:37 -08005721 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005722 if (!hdd_ipa->sap_num_connected_sta &&
5723 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005724 if ((false == hdd_ipa->resource_unloading)
5725 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305726 hdd_ipa->activated_fw_pipe) &&
5727 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005728 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5729 }
5730
Yun Park9b5030f2016-11-08 12:02:37 -08005731 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jiad9d472c92017-07-28 14:05:31 +08005732 hdd_ipa->sta_connected) {
5733 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005734 hdd_ipa_uc_offload_enable_disable(
5735 hdd_get_adapter(hdd_ipa->hdd_ctx,
5736 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005737 SIR_STA_RX_DATA_OFFLOAD, false);
jiad9d472c92017-07-28 14:05:31 +08005738 } else {
5739 qdf_mutex_release(&hdd_ipa->event_lock);
5740 }
Yun Park8f289c82016-10-18 16:38:21 -07005741 } else {
5742 qdf_mutex_release(&hdd_ipa->event_lock);
5743 }
Yun Parkfec73dc2017-09-06 10:40:07 -07005744
Yun Park199c2ed2017-10-02 11:24:22 -07005745 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005746 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005747 break;
5748
5749 default:
5750 return 0;
5751 }
5752
Yun Park6c86a662017-10-05 16:09:15 -07005753 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
5754 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005755 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305756 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005757 return -ENOMEM;
5758 }
5759
Yun Park6c86a662017-10-05 16:09:15 -07005760 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
5761 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), adapter->dev->name,
5762 IPA_RESOURCE_NAME_MAX);
5763 memcpy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, ETH_ALEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005764
Srinivas Girigowda97852372017-03-06 16:52:59 -08005765 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Yun Park6c86a662017-10-05 16:09:15 -07005766 QDF_IPA_WLAN_MSG_NAME(msg),
5767 QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005768
5769 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5770
5771 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005772 hdd_err("%s: Evt: %d fail:%d",
Yun Park6c86a662017-10-05 16:09:15 -07005773 QDF_IPA_WLAN_MSG_NAME(msg),
5774 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305775 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005776 return ret;
5777 }
5778
5779 hdd_ipa->stats.num_send_msg++;
5780
5781end:
5782 return ret;
5783}
5784
5785/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005786 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005787 * @adapter: adapter upon which the event was received
5788 * @sta_id: station id for the event
5789 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5790 * @mac_address: MAC address associated with the event
5791 *
5792 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5793 *
5794 * Return: 0 on success, negative errno value on error
5795 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005796int hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005797 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5798{
Yun Park6c86a662017-10-05 16:09:15 -07005799 qdf_ipa_wlan_event_t type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005800 int ret = 0;
5801
5802 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005803
Leo Changa202b522016-10-14 16:13:50 -07005804 /* Data path offload only support for STA and SAP mode */
5805 if ((QDF_STA_MODE == adapter->device_mode) ||
5806 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005807 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005808
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005809 cds_ssr_unprotect(__func__);
5810
5811 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005812}
5813
5814/**
5815 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5816 * @hdd_ipa: Global HDD IPA context
Yun Parka4bb37c2017-12-08 16:14:22 -08005817 * @is_loading: Indicate if invoked during loading
Mohit Khannafa99aea2016-05-12 21:43:13 -07005818 *
5819 * Return: None
5820 */
5821static void
Yun Parka4bb37c2017-12-08 16:14:22 -08005822hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa, bool is_loading)
Mohit Khannafa99aea2016-05-12 21:43:13 -07005823{
5824 unsigned int pending_event_count;
5825 struct ipa_uc_pending_event *pending_event = NULL;
5826
5827 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005828 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07005829 "Pending Event Count %d", pending_event_count);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005830 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005831 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07005832 "No Pending Event");
Mohit Khannafa99aea2016-05-12 21:43:13 -07005833 return;
5834 }
5835
5836 qdf_list_remove_front(&hdd_ipa->pending_event,
5837 (qdf_list_node_t **)&pending_event);
5838 while (pending_event != NULL) {
Yun Parka4bb37c2017-12-08 16:14:22 -08005839 if (pending_event->is_loading == is_loading)
5840 __hdd_ipa_wlan_evt(pending_event->adapter,
5841 pending_event->sta_id,
5842 pending_event->type,
5843 pending_event->mac_addr);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005844 qdf_mem_free(pending_event);
5845 pending_event = NULL;
5846 qdf_list_remove_front(&hdd_ipa->pending_event,
5847 (qdf_list_node_t **)&pending_event);
5848 }
5849}
5850
5851/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005852 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5853 * @state: IPA RM state value
5854 *
5855 * Return: ASCII string representing the IPA RM state
5856 */
5857static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5858{
5859 switch (state) {
5860 case HDD_IPA_RM_RELEASED:
5861 return "RELEASED";
5862 case HDD_IPA_RM_GRANT_PENDING:
5863 return "GRANT_PENDING";
5864 case HDD_IPA_RM_GRANTED:
5865 return "GRANTED";
5866 }
5867
5868 return "UNKNOWN";
5869}
5870
5871/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005872 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005873 * @hdd_ctx: HDD global context
5874 *
5875 * Allocate hdd_ipa resources, ipa pipe resource and register
5876 * wlan interface with IPA module.
5877 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305878 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005879 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005880static QDF_STATUS __hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005881{
5882 struct hdd_ipa_priv *hdd_ipa = NULL;
5883 int ret, i;
5884 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005885 struct ol_txrx_pdev_t *pdev = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07005886 qdf_ipa_rm_perf_profile_t profile;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005887
5888 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305889 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005890
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08005891 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Park199c2ed2017-10-02 11:24:22 -07005892
Yun Parkbaa62862017-01-18 13:43:34 -08005893 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005894 if (!pdev) {
5895 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5896 goto fail_return;
5897 }
5898
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305899 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005900 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305901 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005902 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005903 }
5904
5905 hdd_ctx->hdd_ipa = hdd_ipa;
5906 ghdd_ipa = hdd_ipa;
5907 hdd_ipa->hdd_ctx = hdd_ctx;
5908 hdd_ipa->num_iface = 0;
5909
5910 /* Create the interface context */
5911 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5912 iface_context = &hdd_ipa->iface_context[i];
5913 iface_context->hdd_ipa = hdd_ipa;
5914 iface_context->cons_client =
5915 hdd_ipa_adapter_2_client[i].cons_client;
5916 iface_context->prod_client =
5917 hdd_ipa_adapter_2_client[i].prod_client;
5918 iface_context->iface_id = i;
5919 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305920 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005921 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005922
Leo Chang69c39692016-10-12 20:11:12 -07005923 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305924 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07005925 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305926 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005927 qdf_list_create(&hdd_ipa->pending_event, 1000);
5928 qdf_mutex_create(&hdd_ipa->event_lock);
5929 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005930
5931 ret = hdd_ipa_setup_rm(hdd_ipa);
5932 if (ret)
5933 goto fail_setup_rm;
5934
Yun Park9281cb72017-11-30 11:14:30 -08005935 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++)
5936 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
5937 sizeof(struct hdd_ipa_sys_pipe));
5938
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005939 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5940 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305941 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005942 hdd_ipa->sap_num_connected_sta = 0;
5943 hdd_ipa->ipa_tx_packets_diff = 0;
5944 hdd_ipa->ipa_rx_packets_diff = 0;
5945 hdd_ipa->ipa_p_tx_packets = 0;
5946 hdd_ipa->ipa_p_rx_packets = 0;
5947 hdd_ipa->resource_loading = false;
5948 hdd_ipa->resource_unloading = false;
5949 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005950 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08005951 hdd_ipa->wdi_enabled = false;
Yun Park9281cb72017-11-30 11:14:30 -08005952 /* Setup IPA system pipes */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005953 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5954 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5955 if (ret)
5956 goto fail_create_sys_pipe;
5957 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005958 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5959 goto fail_create_sys_pipe;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005960 } else {
5961 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5962 if (ret)
5963 goto fail_create_sys_pipe;
5964 }
5965
Yun Park66f24c42017-03-20 10:39:47 -07005966 /* When IPA clock scaling is disabled, initialze maximum clock */
5967 if (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)) {
5968 profile.max_supported_bandwidth_mbps = 800;
5969 hdd_debug("IPA clock scaling is disabled.");
5970 hdd_debug("Set initial CONS/PROD perf: %d",
5971 profile.max_supported_bandwidth_mbps);
5972 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
5973 &profile);
5974 if (ret) {
5975 hdd_err("RM CONS set perf profile failed: %d", ret);
5976 goto fail_create_sys_pipe;
5977 }
5978
5979 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
5980 &profile);
5981 if (ret) {
5982 hdd_err("RM PROD set perf profile failed: %d", ret);
5983 goto fail_create_sys_pipe;
5984 }
5985 }
5986
Yun Park777d7242017-03-30 15:38:33 -07005987 init_completion(&hdd_ipa->ipa_resource_comp);
5988
Yun Parke4239802018-01-09 11:01:40 -08005989 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305990 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005991
5992fail_create_sys_pipe:
5993 hdd_ipa_destroy_rm_resource(hdd_ipa);
5994fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305995 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305996 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005997 hdd_ctx->hdd_ipa = NULL;
5998 ghdd_ipa = NULL;
5999fail_return:
Rajeev Kumar3887f9b2018-01-10 11:24:01 -08006000 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: fail");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306001 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006002}
6003
6004/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006005 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
6006 * @hdd_ctx: HDD global context
6007 *
6008 * Allocate hdd_ipa resources, ipa pipe resource and register
6009 * wlan interface with IPA module.
6010 *
6011 * Return: QDF_STATUS enumeration
6012 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07006013QDF_STATUS hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006014{
6015 QDF_STATUS ret;
6016
6017 cds_ssr_protect(__func__);
6018 ret = __hdd_ipa_init(hdd_ctx);
6019 cds_ssr_unprotect(__func__);
6020
6021 return ret;
6022}
6023
Arun Khandavallicc544b32017-01-30 19:52:16 +05306024
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006025/**
Govind Singh1dab23b2017-08-12 13:31:00 +05306026 * __hdd_ipa_flush - flush IPA exception path SKB's
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006027 * @hdd_ctx: HDD global context
6028 *
Govind Singh1dab23b2017-08-12 13:31:00 +05306029 * Return: none
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006030 */
Govind Singh1dab23b2017-08-12 13:31:00 +05306031static void __hdd_ipa_flush(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006032{
6033 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
Nirav Shahcbc6d722016-03-01 16:24:53 +05306034 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006035 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
6036
6037 if (!hdd_ipa_is_enabled(hdd_ctx))
Govind Singh1dab23b2017-08-12 13:31:00 +05306038 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006039
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006040 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006041
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306042 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006043
Nirav Shahcbc6d722016-03-01 16:24:53 +05306044 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
6045 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306046 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006047
6048 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07006049 if (pm_tx_cb->ipa_tx_desc)
6050 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006051
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306052 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006053 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306054 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Govind Singh1dab23b2017-08-12 13:31:00 +05306055}
6056
6057/**
6058 * __hdd_ipa_cleanup - IPA cleanup function
6059 * @hdd_ctx: HDD global context
6060 *
6061 * Return: QDF_STATUS enumeration
6062 */
6063static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
6064{
6065 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
6066 int i;
6067 struct hdd_ipa_iface_context *iface_context = NULL;
6068
6069 if (!hdd_ipa_is_enabled(hdd_ctx))
6070 return QDF_STATUS_SUCCESS;
6071
6072 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
6073 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
6074 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6075 }
6076
6077 /* Teardown IPA sys_pipe for MCC */
6078 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
6079 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6080
6081 hdd_ipa_destroy_rm_resource(hdd_ipa);
6082
6083 __hdd_ipa_flush(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006084
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306085 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006086 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006087
6088 /* destory the interface lock */
6089 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6090 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306091 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092 }
6093
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006094 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08006095 if (ipa_uc_dereg_rdyCB())
6096 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
6097 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006098 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306099 qdf_mutex_destroy(&hdd_ipa->event_lock);
6100 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07006101 qdf_list_destroy(&hdd_ipa->pending_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006102
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006103 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6104 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
Yun Park6edb2172018-01-14 00:18:05 -08006105 qdf_mem_free(hdd_ipa->uc_op_work[i].msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006106 hdd_ipa->uc_op_work[i].msg = NULL;
6107 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006108 }
6109
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306110 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006111 hdd_ctx->hdd_ipa = NULL;
6112
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306113 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006114}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006115
6116/**
Govind Singh1dab23b2017-08-12 13:31:00 +05306117 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_flush
6118 * @hdd_ctx: HDD global context
6119 *
6120 * Return: None
6121 */
6122void hdd_ipa_flush(struct hdd_context *hdd_ctx)
6123{
6124 cds_ssr_protect(__func__);
6125 __hdd_ipa_flush(hdd_ctx);
6126 cds_ssr_unprotect(__func__);
6127}
6128
6129/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006130 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
6131 * @hdd_ctx: HDD global context
6132 *
6133 * Return: QDF_STATUS enumeration
6134 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07006135QDF_STATUS hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006136{
6137 QDF_STATUS ret;
6138
6139 cds_ssr_protect(__func__);
6140 ret = __hdd_ipa_cleanup(hdd_ctx);
6141 cds_ssr_unprotect(__func__);
6142
6143 return ret;
6144}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006145#endif /* IPA_OFFLOAD */