blob: fb0754340c71a34d7aaab671c8035a2c2b2b9fa7 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
jge62037862016-12-09 10:44:33 +08002 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ipa.c
30 *
31 * WLAN HDD and ipa interface implementation
32 * Originally written by Qualcomm Atheros, Inc
33 */
34
35#ifdef IPA_OFFLOAD
36
37/* Include Files */
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];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800312};
313
314/**
315 * struct uc_rm_work_struct
316 * @work: uC RM work
317 * @event: IPA RM event
318 */
319struct uc_rm_work_struct {
320 struct work_struct work;
Yun Park6c86a662017-10-05 16:09:15 -0700321 qdf_ipa_rm_event_t event;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800322};
323
324/**
325 * struct uc_op_work_struct
326 * @work: uC OP work
327 * @msg: OP message
328 */
329struct uc_op_work_struct {
330 struct work_struct work;
331 struct op_msg_type *msg;
332};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800333
334/**
335 * struct uc_rt_debug_info
336 * @time: system time
337 * @ipa_excep_count: IPA exception packet count
338 * @rx_drop_count: IPA Rx drop packet count
339 * @net_sent_count: IPA Rx packet sent to network stack count
340 * @rx_discard_count: IPA Rx discard packet count
Yun Parkb187d542016-11-14 18:10:04 -0800341 * @tx_fwd_ok_count: IPA Tx forward success packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800342 * @tx_fwd_count: IPA Tx forward packet count
343 * @rx_destructor_call: IPA Rx packet destructor count
344 */
345struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530346 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800347 uint64_t ipa_excep_count;
348 uint64_t rx_drop_count;
349 uint64_t net_sent_count;
350 uint64_t rx_discard_count;
Yun Parkb187d542016-11-14 18:10:04 -0800351 uint64_t tx_fwd_ok_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800352 uint64_t tx_fwd_count;
353 uint64_t rx_destructor_call;
354};
355
Yun Park637d6482016-10-05 10:51:33 -0700356#ifdef FEATURE_METERING
357struct ipa_uc_sharing_stats {
358 uint64_t ipv4_rx_packets;
359 uint64_t ipv4_rx_bytes;
360 uint64_t ipv6_rx_packets;
361 uint64_t ipv6_rx_bytes;
362 uint64_t ipv4_tx_packets;
363 uint64_t ipv4_tx_bytes;
364 uint64_t ipv6_tx_packets;
365 uint64_t ipv6_tx_bytes;
366};
367
368struct ipa_uc_quota_rsp {
369 uint8_t success;
370 uint8_t reserved[3];
371 uint32_t quota_lo; /* quota limit low bytes */
372 uint32_t quota_hi; /* quota limit high bytes */
373};
374
375struct ipa_uc_quota_ind {
376 uint64_t quota_bytes; /* quota limit in bytes */
377};
378#endif
379
Yun Park52b2b992016-09-22 15:49:51 -0700380/**
381 * struct hdd_ipa_tx_desc
382 * @link: link to list head
383 * @priv: pointer to priv list entry
384 * @id: Tx desc idex
385 * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor
386 */
387struct hdd_ipa_tx_desc {
388 struct list_head link;
389 void *priv;
390 uint32_t id;
Yun Park6c86a662017-10-05 16:09:15 -0700391 qdf_ipa_rx_data_t *ipa_tx_desc_ptr;
Yun Park52b2b992016-09-22 15:49:51 -0700392};
393
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800394struct hdd_ipa_priv {
395 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
396 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
397 uint8_t num_iface;
398 enum hdd_ipa_rm_state rm_state;
399 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530400 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800401 * APIs as it is taken care gracefully. Without this, kernel would throw
402 * an warning if spin_lock_bh is used while IRQ is disabled
403 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530404 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800405 struct uc_rm_work_struct uc_rm_work;
406 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530407 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800408 struct delayed_work wake_lock_work;
409 bool wake_lock_released;
410
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800411 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530412 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800413 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530414 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800415 bool suspended;
416
Yun Park52b2b992016-09-22 15:49:51 -0700417 qdf_spinlock_t q_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800418
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800419 struct list_head pend_desc_head;
Yun Park52b2b992016-09-22 15:49:51 -0700420 struct hdd_ipa_tx_desc *tx_desc_list;
421 struct list_head free_tx_desc_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800422
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700423 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800424 struct hdd_ipa_stats stats;
425
426 struct notifier_block ipv4_notifier;
427 uint32_t curr_prod_bw;
428 uint32_t curr_cons_bw;
429
430 uint8_t activated_fw_pipe;
431 uint8_t sap_num_connected_sta;
432 uint8_t sta_connected;
433 uint32_t tx_pipe_handle;
434 uint32_t rx_pipe_handle;
435 bool resource_loading;
436 bool resource_unloading;
437 bool pending_cons_req;
438 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530439 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530440 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700441 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800442 uint32_t ipa_tx_packets_diff;
443 uint32_t ipa_rx_packets_diff;
444 uint32_t ipa_p_tx_packets;
445 uint32_t ipa_p_rx_packets;
446 uint32_t stat_req_reason;
447 uint64_t ipa_tx_forward;
448 uint64_t ipa_rx_discard;
449 uint64_t ipa_rx_net_send_count;
Yun Park46255682017-10-09 15:56:34 -0700450 uint64_t ipa_rx_internal_drop_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800451 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530452 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800453 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
454 unsigned int rt_buf_fill_index;
Yun Park6c86a662017-10-05 16:09:15 -0700455 qdf_ipa_wdi_in_params_t cons_pipe_in;
456 qdf_ipa_wdi_in_params_t prod_pipe_in;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800457 bool uc_loaded;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800458 bool wdi_enabled;
Anurag Chouhan210db072016-02-22 18:42:15 +0530459 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530460 qdf_mutex_t rt_debug_lock;
461 qdf_mutex_t ipa_lock;
Yun Parkb4f591d2017-03-29 15:51:01 -0700462
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800463 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
464 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Yun Park637d6482016-10-05 10:51:33 -0700465#ifdef FEATURE_METERING
466 struct ipa_uc_sharing_stats ipa_sharing_stats;
467 struct ipa_uc_quota_rsp ipa_quota_rsp;
468 struct ipa_uc_quota_ind ipa_quota_ind;
469 struct completion ipa_uc_sharing_stats_comp;
470 struct completion ipa_uc_set_quota_comp;
471#endif
Yun Park777d7242017-03-30 15:38:33 -0700472 struct completion ipa_resource_comp;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800473};
474
Leo Changcc923e22016-06-16 15:29:03 -0700475#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
476#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
478#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
479#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
480#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
481#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700482#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
483 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800484
485#define HDD_IPA_GET_IFACE_ID(_data) \
486 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
487
488#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530489 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800490 "%s:%d: "fmt, __func__, __LINE__, ## args)
491
Govind Singhb6a89772016-08-12 11:23:35 +0530492#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
493 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
494 "%s:%d: "fmt, __func__, __LINE__, ## args)
495
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800496#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
497 do { \
Yun Parkec845302016-12-15 09:22:57 -0800498 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \
499 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800500 } while (0)
501
502#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
503 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
504
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800505#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
506
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700507#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)
Leo Chang63d73612016-10-18 18:09:43 -0700508#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800509#else
510/* Do nothing */
Leo Chang63d73612016-10-18 18:09:43 -0700511#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700512#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800513
Yun Park0dad1002017-07-14 14:57:01 -0700514#define HDD_IPA_DBG_DUMP_RX_LEN 84
Yun Parkb187d542016-11-14 18:10:04 -0800515#define HDD_IPA_DBG_DUMP_TX_LEN 48
516
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800517static struct hdd_ipa_adapter_2_client {
Yun Park6c86a662017-10-05 16:09:15 -0700518 qdf_ipa_client_type_t cons_client;
519 qdf_ipa_client_type_t prod_client;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800520} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
521 {
522 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
523 }, {
524 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
525 }, {
526 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
527 },
528};
529
Yun Park637d6482016-10-05 10:51:33 -0700530#ifdef FEATURE_METERING
531#define IPA_UC_SHARING_STATES_WAIT_TIME 500
532#define IPA_UC_SET_QUOTA_WAIT_TIME 500
533#endif
534
Yun Park777d7242017-03-30 15:38:33 -0700535#define IPA_RESOURCE_COMP_WAIT_TIME 100
536
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800537static struct hdd_ipa_priv *ghdd_ipa;
538
539/* Local Function Prototypes */
Yun Park6c86a662017-10-05 16:09:15 -0700540static void hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800541 unsigned long data);
Yun Park6c86a662017-10-05 16:09:15 -0700542static void hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800543 unsigned long data);
Yun Parkb4f591d2017-03-29 15:51:01 -0700544#ifdef FEATURE_METERING
Yun Park6c86a662017-10-05 16:09:15 -0700545static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Parkb4f591d2017-03-29 15:51:01 -0700546 void *data);
547#else
548static void hdd_ipa_wdi_meter_notifier_cb(void);
549#endif
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800550static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800551
552static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -0700553static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800554
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800555#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
556 defined(IPA_CLIENT_IS_MHI_CONS))
557/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800558 * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
559 * @priv_ctxt: hdd ipa local context
560 *
561 * Will be called by IPA context.
562 * It's atomic context, then should be scheduled to kworker thread
563 *
564 * Return: None
565 */
566static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt)
567{
568 struct hdd_ipa_priv *hdd_ipa;
569 struct op_msg_type *msg;
570 struct uc_op_work_struct *uc_op_work;
571
572 if (priv_ctxt == NULL) {
573 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context");
574 return;
575 }
576
577 hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt;
578 msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg));
579 if (!msg) {
580 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails");
581 return;
582 }
583
584 msg->op_code = HDD_IPA_UC_OPCODE_UC_READY;
585
586 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
587
588 /* When the same uC OPCODE is already pended, just return */
589 if (uc_op_work->msg)
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530590 goto done;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800591
592 uc_op_work->msg = msg;
593 schedule_work(&uc_op_work->work);
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530594
jiadd91a6842017-08-01 14:46:02 +0800595 /* work handler will free the msg buffer */
596 return;
597
SaidiReddy Yenuga466b3ce2017-05-02 18:50:25 +0530598done:
599 qdf_mem_free(msg);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800600}
601
602/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800603 * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message
604 * @ctrl: WDI control value
605 *
606 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
607 *
608 * Return: 0 on message send to ipa, -1 on failure
609 */
610static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
611{
Yun Park6c86a662017-10-05 16:09:15 -0700612 qdf_ipa_msg_meta_t meta;
613 qdf_ipa_wlan_msg_t *ipa_msg;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800614 int ret = 0;
615
616 /* WDI enable message to IPA */
Yun Park6c86a662017-10-05 16:09:15 -0700617 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg);
618 ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800619 if (ipa_msg == NULL) {
620 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
621 "msg allocation failed");
622 return -ENOMEM;
623 }
624
625 if (ctrl == true)
Yun Park6c86a662017-10-05 16:09:15 -0700626 QDF_IPA_MSG_META_MSG_TYPE(&meta) = WLAN_WDI_ENABLE;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800627 else
Yun Park6c86a662017-10-05 16:09:15 -0700628 QDF_IPA_MSG_META_MSG_TYPE(&meta) = WLAN_WDI_DISABLE;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800629
Srinivas Girigowda97852372017-03-06 16:52:59 -0800630 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park6c86a662017-10-05 16:09:15 -0700631 "ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
632 ret = qdf_ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800633 if (ret) {
634 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
635 "ipa_send_msg(Evt:%d)-fail=%d",
Yun Park6c86a662017-10-05 16:09:15 -0700636 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800637 qdf_mem_free(ipa_msg);
638 }
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800639 return ret;
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800640}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800641
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800642/**
643 * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
644 * @hdd_ipa: HDD IPA local context
645 *
646 * Register IPA UC ready callback function to IPA kernel driver
647 * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
648 * open WDI pipe after WLAN driver loading finished
649 *
650 * Return: 0 Success
651 * -EPERM Registration fail
652 */
653static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
654{
Yun Park6c86a662017-10-05 16:09:15 -0700655 qdf_ipa_wdi_uc_ready_params_t uc_ready_param;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800656 int ret = 0;
657
658 hdd_ipa->uc_loaded = false;
Yun Park6c86a662017-10-05 16:09:15 -0700659 QDF_IPA_UC_READY_PARAMS_PRIV(&uc_ready_param) = (void *)hdd_ipa;
660 QDF_IPA_UC_READY_PARAMS_NOTIFY(&uc_ready_param) =
661 hdd_ipa_uc_loaded_uc_cb;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800662 if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
663 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
664 "UC Ready CB register fail");
665 return -EPERM;
666 }
Yun Park6c86a662017-10-05 16:09:15 -0700667 if (false != QDF_IPA_UC_READY_PARAMS_IS_UC_READY(&uc_ready_param)) {
Srinivas Girigowda2b5d47c2017-03-29 00:28:46 -0700668 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -0800669 hdd_ipa->uc_loaded = true;
670 } else {
671 ret = hdd_ipa_uc_send_wdi_control_msg(false);
672 }
673
674 return ret;
675}
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800676#else
Manikandan Mohan153a4c32017-02-16 15:04:30 -0800677static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
678{
679 hdd_ipa->uc_loaded = true;
680 return 0;
681}
682
683static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
684{
685 return 0;
686}
687#endif
688
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800689/**
690 * hdd_ipa_is_enabled() - Is IPA enabled?
691 * @hdd_ctx: Global HDD context
692 *
693 * Return: true if IPA is enabled, false otherwise
694 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700695bool hdd_ipa_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800696{
697 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
698}
699
700/**
701 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
702 * @hdd_ctx: Global HDD context
703 *
704 * Return: true if IPA uC offload is enabled, false otherwise
705 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700706bool hdd_ipa_uc_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800707{
708 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
709}
710
711/**
712 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
713 * @hdd_ctx: Global HDD context
714 *
715 * Return: true if STA mode IPA uC offload is enabled, false otherwise
716 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700717static inline bool hdd_ipa_uc_sta_is_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800718{
719 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
720}
721
722/**
Guolei Bianca144d82016-11-10 11:07:42 +0800723 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
724 * @hdd_ipa: Global HDD IPA context
725 *
726 * Return: None
727 */
Guolei Bianca144d82016-11-10 11:07:42 +0800728static inline void hdd_ipa_uc_sta_reset_sta_connected(
729 struct hdd_ipa_priv *hdd_ipa)
730{
Yun Park637d6482016-10-05 10:51:33 -0700731 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800732 hdd_ipa->sta_connected = 0;
Yun Park637d6482016-10-05 10:51:33 -0700733 qdf_mutex_release(&hdd_ipa->ipa_lock);
Guolei Bianca144d82016-11-10 11:07:42 +0800734}
Guolei Bianca144d82016-11-10 11:07:42 +0800735
736/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800737 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
738 * @hdd_ipa: Global HDD IPA context
739 *
740 * Return: true if pre-filter is enabled, otherwise false
741 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700742static inline bool hdd_ipa_is_pre_filter_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800743{
744 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
745 HDD_IPA_PRE_FILTER_ENABLE_MASK);
746}
747
748/**
749 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
750 * @hdd_ipa: Global HDD IPA context
751 *
752 * Return: true if IPv6 is enabled, otherwise false
753 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700754static inline bool hdd_ipa_is_ipv6_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800755{
756 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
757}
758
759/**
760 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
761 * @hdd_ipa: Global HDD IPA context
762 *
763 * Return: true if resource manager is enabled, otherwise false
764 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700765static inline bool hdd_ipa_is_rm_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800766{
767 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
768}
769
770/**
771 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
772 * @hdd_ipa: Global HDD IPA context
773 *
774 * Return: true if resource manager is enabled, otherwise false
775 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700776static inline bool hdd_ipa_is_rt_debugging_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800777{
778 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
779}
780
781/**
782 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
783 * @hdd_ipa: Global HDD IPA context
784 *
785 * Return: true if clock scaling is enabled, otherwise false
786 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700787static inline bool hdd_ipa_is_clk_scaling_enabled(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800788{
789 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
790 HDD_IPA_CLK_SCALING_ENABLE_MASK |
791 HDD_IPA_RM_ENABLE_MASK);
792}
793
794/**
795 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
796 * @ctext: pointer to hdd context.
797 *
798 * If rt debug enabled, periodically called, and fill debug buffer
799 *
800 * Return: none
801 */
802static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
803{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700804 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800805 struct hdd_ipa_priv *hdd_ipa;
806 struct uc_rt_debug_info *dump_info = NULL;
807
808 if (wlan_hdd_validate_context(hdd_ctx))
809 return;
810
811 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700812 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813 return;
814 }
815
816 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
817
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530818 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800819 dump_info = &hdd_ipa->rt_bug_buffer[
820 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
821
Deepthi Gowri6acee342016-10-28 15:00:38 +0530822 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800823 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
Yun Park46255682017-10-09 15:56:34 -0700824 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internal_drop_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800825 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800826 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
Yun Parkb187d542016-11-14 18:10:04 -0800827 dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok;
828 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800829 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
830 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530831 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800832
Anurag Chouhan210db072016-02-22 18:42:15 +0530833 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
835}
836
837/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700838 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800839 * @hdd_ctx: pointer to hdd context.
840 *
841 * If rt debug enabled, dump debug buffer contents based on requirement
842 *
843 * Return: none
844 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700845static void __hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800846{
847 struct hdd_ipa_priv *hdd_ipa;
848 unsigned int dump_count;
849 unsigned int dump_index;
850 struct uc_rt_debug_info *dump_info = NULL;
851
852 if (wlan_hdd_validate_context(hdd_ctx))
853 return;
854
855 hdd_ipa = hdd_ctx->hdd_ipa;
856 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700857 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800858 return;
859 }
860
Chris Guo1751acf2017-07-03 14:09:01 +0800861 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
862 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -0700863 "IPA RT debug is not enabled");
Chris Guo1751acf2017-07-03 14:09:01 +0800864 return;
865 }
866
Yun Park46255682017-10-09 15:56:34 -0700867 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800868 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Yun Park46255682017-10-09 15:56:34 -0700869 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Parkb187d542016-11-14 18:10:04 -0800870 " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800871
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530872 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873 for (dump_count = 0;
874 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
875 dump_count++) {
876 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
877 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
878 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Yun Park46255682017-10-09 15:56:34 -0700879 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530880 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800881 dump_info->time, dump_info->ipa_excep_count,
882 dump_info->rx_drop_count, dump_info->net_sent_count,
Yun Parkb187d542016-11-14 18:10:04 -0800883 dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800884 dump_info->rx_destructor_call,
885 dump_info->rx_discard_count);
886 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530887 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Yun Park46255682017-10-09 15:56:34 -0700888 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800889 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
890}
891
892/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700893 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
894 * __hdd_ipa_uc_rt_debug_host_dump
895 * @hdd_ctx: pointer to hdd context.
896 *
897 * If rt debug enabled, dump debug buffer contents based on requirement
898 *
899 * Return: none
900 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700901void hdd_ipa_uc_rt_debug_host_dump(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700902{
903 cds_ssr_protect(__func__);
904 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
905 cds_ssr_unprotect(__func__);
906}
907
908/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800909 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
910 * @ctext: pointer to hdd context.
911 *
912 * periodically called by timer expire
913 * will try to alloc dummy memory and detect out of memory condition
914 * if out of memory detected, dump wlan-ipa stats
915 *
916 * Return: none
917 */
918static void hdd_ipa_uc_rt_debug_handler(void *ctext)
919{
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700920 struct hdd_context *hdd_ctx = (struct hdd_context *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700921 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800922 void *dummy_ptr = NULL;
923
924 if (wlan_hdd_validate_context(hdd_ctx))
925 return;
926
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700927 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
928
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700930 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
931 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800932 return;
933 }
934
935 /* Allocate dummy buffer periodically and free immediately. this will
936 * proactively detect OOM and if allocation fails dump ipa stats
937 */
938 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
939 GFP_KERNEL | GFP_ATOMIC);
940 if (!dummy_ptr) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
942 hdd_ipa_uc_stat_request(
Yun Park637d6482016-10-05 10:51:33 -0700943 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
944 HDD_IPA_UC_STAT_REASON_DEBUG);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800945 } else {
946 kfree(dummy_ptr);
947 }
948
Anurag Chouhan210db072016-02-22 18:42:15 +0530949 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800950 HDD_IPA_UC_RT_DEBUG_PERIOD);
951}
952
953/**
Yun Parkb187d542016-11-14 18:10:04 -0800954 * hdd_ipa_uc_rt_debug_destructor() - called by data packet free
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800955 * @skb: packet pinter
956 *
957 * when free data packet, will be invoked by wlan client and will increase
958 * free counter
959 *
960 * Return: none
961 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700962static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800963{
964 if (!ghdd_ipa) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700965 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "invalid hdd context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800966 return;
967 }
968
969 ghdd_ipa->ipa_rx_destructor_count++;
970}
971
972/**
Yun Parkb187d542016-11-14 18:10:04 -0800973 * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800974 * @hdd_ctx: hdd main context
975 *
976 * free all rt debugging resources
977 *
978 * Return: none
979 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -0700980static void hdd_ipa_uc_rt_debug_deinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800981{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700982 struct hdd_ipa_priv *hdd_ipa;
983
984 if (wlan_hdd_validate_context(hdd_ctx))
985 return;
986
987 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800988
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530989 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990
991 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -0700992 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
993 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994 return;
995 }
996
Anurag Chouhan210db072016-02-22 18:42:15 +0530997 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -0800998 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
999 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
1000 }
1001 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
1002
1003 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +05301004 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
1005 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006 }
Anurag Chouhan210db072016-02-22 18:42:15 +05301007 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001008}
1009
1010/**
Yun Parkb187d542016-11-14 18:10:04 -08001011 * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001012 * @hdd_ctx: hdd main context
1013 *
1014 * alloc and initialize all rt debugging resources
1015 *
1016 * Return: none
1017 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001018static void hdd_ipa_uc_rt_debug_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001020 struct hdd_ipa_priv *hdd_ipa;
1021
Chris Guo1751acf2017-07-03 14:09:01 +08001022 if (wlan_hdd_validate_context_in_loading(hdd_ctx))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001023 return;
1024
1025 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001026
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301027 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301029 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001030 sizeof(struct uc_rt_debug_info) *
1031 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
1032 hdd_ipa->ipa_tx_forward = 0;
1033 hdd_ipa->ipa_rx_discard = 0;
1034 hdd_ipa->ipa_rx_net_send_count = 0;
Yun Park46255682017-10-09 15:56:34 -07001035 hdd_ipa->ipa_rx_internal_drop_count = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001036 hdd_ipa->ipa_rx_destructor_count = 0;
1037
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001038 /* Reatime debug enable on feature enable */
1039 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Yun Parkb4f591d2017-03-29 15:51:01 -07001040 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1041 "IPA RT debug is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042 return;
1043 }
Yun Parkdfc1da52016-11-15 14:50:11 -08001044
1045 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
1046 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
1047 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
1048 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
1049
Anurag Chouhan210db072016-02-22 18:42:15 +05301050 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001051 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +05301052 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001053 HDD_IPA_UC_RT_DEBUG_PERIOD);
1054
1055}
1056
1057/**
Yun Parkb187d542016-11-14 18:10:04 -08001058 * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct
1059 * @hdd_ipa: HDD IPA struct
1060 *
1061 * Dump entries in struct hdd_ipa
1062 *
1063 * Return: none
1064 */
1065static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
1066{
1067 int i;
1068
1069 /* HDD IPA */
Yun Park46255682017-10-09 15:56:34 -07001070 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1071 "\n==== HDD IPA ====\n"
Yun Parkb187d542016-11-14 18:10:04 -08001072 "num_iface: %d\n"
1073 "rm_state: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001074 "rm_lock: %pK\n"
1075 "uc_rm_work: %pK\n"
1076 "uc_op_work: %pK\n"
1077 "wake_lock: %pK\n"
1078 "wake_lock_work: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001079 "wake_lock_released: %d\n"
Yun Parkb187d542016-11-14 18:10:04 -08001080 "tx_ref_cnt: %d\n"
1081 "pm_queue_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001082 "\thead: %pK\n"
1083 "\ttail: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001084 "\tqlen: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001085 "pm_work: %pK\n"
1086 "pm_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001087 "suspended: %d\n",
1088 hdd_ipa->num_iface,
1089 hdd_ipa->rm_state,
1090 &hdd_ipa->rm_lock,
1091 &hdd_ipa->uc_rm_work,
1092 &hdd_ipa->uc_op_work,
1093 &hdd_ipa->wake_lock,
1094 &hdd_ipa->wake_lock_work,
1095 hdd_ipa->wake_lock_released,
Yun Parkb187d542016-11-14 18:10:04 -08001096 hdd_ipa->tx_ref_cnt.counter,
1097 hdd_ipa->pm_queue_head.head,
1098 hdd_ipa->pm_queue_head.tail,
1099 hdd_ipa->pm_queue_head.qlen,
1100 &hdd_ipa->pm_work,
1101 &hdd_ipa->pm_lock,
1102 hdd_ipa->suspended);
Yun Park46255682017-10-09 15:56:34 -07001103
1104 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1105 "\nq_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001106 "pend_desc_head----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001107 "\tnext: %pK\n"
1108 "\tprev: %pK\n"
1109 "hdd_ctx: %pK\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001110 "stats: %pK\n"
1111 "ipv4_notifier: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001112 "curr_prod_bw: %d\n"
1113 "curr_cons_bw: %d\n"
1114 "activated_fw_pipe: %d\n"
1115 "sap_num_connected_sta: %d\n"
1116 "sta_connected: %d\n",
Yun Parkb187d542016-11-14 18:10:04 -08001117 &hdd_ipa->q_lock,
Yun Parkb187d542016-11-14 18:10:04 -08001118 hdd_ipa->pend_desc_head.next,
1119 hdd_ipa->pend_desc_head.prev,
1120 hdd_ipa->hdd_ctx,
Yun Parkb187d542016-11-14 18:10:04 -08001121 &hdd_ipa->stats,
1122 &hdd_ipa->ipv4_notifier,
1123 hdd_ipa->curr_prod_bw,
1124 hdd_ipa->curr_cons_bw,
1125 hdd_ipa->activated_fw_pipe,
1126 hdd_ipa->sap_num_connected_sta,
Yun Park46255682017-10-09 15:56:34 -07001127 (unsigned int)hdd_ipa->sta_connected);
1128
1129 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1130 "\ntx_pipe_handle: 0x%x\n"
Yun Parkb187d542016-11-14 18:10:04 -08001131 "rx_pipe_handle: 0x%x\n"
1132 "resource_loading: %d\n"
1133 "resource_unloading: %d\n"
1134 "pending_cons_req: %d\n"
1135 "pending_event----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001136 "\tanchor.next: %pK\n"
1137 "\tanchor.prev: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001138 "\tcount: %d\n"
1139 "\tmax_size: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001140 "event_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001141 "ipa_tx_packets_diff: %d\n"
1142 "ipa_rx_packets_diff: %d\n"
1143 "ipa_p_tx_packets: %d\n"
1144 "ipa_p_rx_packets: %d\n"
1145 "stat_req_reason: %d\n",
1146 hdd_ipa->tx_pipe_handle,
1147 hdd_ipa->rx_pipe_handle,
1148 hdd_ipa->resource_loading,
1149 hdd_ipa->resource_unloading,
1150 hdd_ipa->pending_cons_req,
1151 hdd_ipa->pending_event.anchor.next,
1152 hdd_ipa->pending_event.anchor.prev,
1153 hdd_ipa->pending_event.count,
1154 hdd_ipa->pending_event.max_size,
1155 &hdd_ipa->event_lock,
1156 hdd_ipa->ipa_tx_packets_diff,
1157 hdd_ipa->ipa_rx_packets_diff,
1158 hdd_ipa->ipa_p_tx_packets,
1159 hdd_ipa->ipa_p_rx_packets,
1160 hdd_ipa->stat_req_reason);
1161
Yun Park46255682017-10-09 15:56:34 -07001162 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1163 "\ncons_pipe_in----\n"
1164 "\tsys: %pK\n"
1165 "\tdl.comp_ring_base_pa: 0x%x\n"
1166 "\tdl.comp_ring_size: %d\n"
1167 "\tdl.ce_ring_base_pa: 0x%x\n"
1168 "\tdl.ce_door_bell_pa: 0x%x\n"
1169 "\tdl.ce_ring_size: %d\n"
1170 "\tdl.num_tx_buffers: %d\n"
1171 "prod_pipe_in----\n"
1172 "\tsys: %pK\n"
1173 "\tul.rdy_ring_base_pa: 0x%x\n"
1174 "\tul.rdy_ring_size: %d\n"
1175 "\tul.rdy_ring_rp_pa: 0x%x\n"
1176 "uc_loaded: %d\n"
1177 "wdi_enabled: %d\n"
1178 "rt_debug_fill_timer: %pK\n"
1179 "rt_debug_lock: %pK\n"
1180 "ipa_lock: %pK\n",
1181 &hdd_ipa->cons_pipe_in.sys,
1182 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.comp_ring_base_pa,
1183 hdd_ipa->cons_pipe_in.u.dl.comp_ring_size,
1184 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.ce_ring_base_pa,
1185 (unsigned int)hdd_ipa->cons_pipe_in.u.dl.ce_door_bell_pa,
1186 hdd_ipa->cons_pipe_in.u.dl.ce_ring_size,
1187 hdd_ipa->cons_pipe_in.u.dl.num_tx_buffers,
1188 &hdd_ipa->prod_pipe_in.sys,
1189 (unsigned int)hdd_ipa->prod_pipe_in.u.ul.rdy_ring_base_pa,
1190 hdd_ipa->prod_pipe_in.u.ul.rdy_ring_size,
1191 (unsigned int)hdd_ipa->prod_pipe_in.u.ul.rdy_ring_rp_pa,
1192 hdd_ipa->uc_loaded,
1193 hdd_ipa->wdi_enabled,
1194 &hdd_ipa->rt_debug_fill_timer,
1195 &hdd_ipa->rt_debug_lock,
1196 &hdd_ipa->ipa_lock);
1197
1198 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1199 "\nvdev_to_iface----");
1200 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
1201 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1202 "\n\t[%d]=%d", i, hdd_ipa->vdev_to_iface[i]);
1203 }
1204 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1205 "\nvdev_offload_enabled----");
1206 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
1207 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1208 "\n\t[%d]=%d", i, hdd_ipa->vdev_offload_enabled[i]);
1209 }
1210 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1211 "\nassoc_stas_map ----");
Yun Parkb187d542016-11-14 18:10:04 -08001212 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Yun Park46255682017-10-09 15:56:34 -07001213 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1214 "\n\t[%d]: is_reserved=%d, sta_id=%d", i,
Yun Parkb187d542016-11-14 18:10:04 -08001215 hdd_ipa->assoc_stas_map[i].is_reserved,
1216 hdd_ipa->assoc_stas_map[i].sta_id);
1217 }
1218}
1219
1220/**
1221 * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct
1222 * @hdd_ipa: HDD IPA struct
1223 *
1224 * Dump entire struct hdd_ipa_sys_pipe
1225 *
1226 * Return: none
1227 */
1228static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
1229{
1230 int i;
1231
1232 /* IPA SYS Pipes */
Yun Park46255682017-10-09 15:56:34 -07001233 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1234 "\n==== IPA SYS Pipes ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001235
1236 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
1237 struct hdd_ipa_sys_pipe *sys_pipe;
Yun Park6c86a662017-10-05 16:09:15 -07001238 qdf_ipa_sys_connect_params_t *ipa_sys_params;
Yun Parkb187d542016-11-14 18:10:04 -08001239
1240 sys_pipe = &hdd_ipa->sys_pipe[i];
1241 ipa_sys_params = &sys_pipe->ipa_sys_params;
1242
Yun Park46255682017-10-09 15:56:34 -07001243 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1244 "\nsys_pipe[%d]----\n"
Yun Parkb187d542016-11-14 18:10:04 -08001245 "\tconn_hdl: 0x%x\n"
1246 "\tconn_hdl_valid: %d\n"
1247 "\tnat_en: %d\n"
1248 "\thdr_len %d\n"
1249 "\thdr_additional_const_len: %d\n"
1250 "\thdr_ofst_pkt_size_valid: %d\n"
1251 "\thdr_ofst_pkt_size: %d\n"
1252 "\thdr_little_endian: %d\n"
1253 "\tmode: %d\n"
1254 "\tclient: %d\n"
1255 "\tdesc_fifo_sz: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001256 "\tpriv: %pK\n"
1257 "\tnotify: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001258 "\tskip_ep_cfg: %d\n"
1259 "\tkeep_ipa_awake: %d\n",
1260 i,
1261 sys_pipe->conn_hdl,
1262 sys_pipe->conn_hdl_valid,
Yun Park6c86a662017-10-05 16:09:15 -07001263 QDF_IPA_SYS_PARAMS_NAT_EN(ipa_sys_params),
1264 QDF_IPA_SYS_PARAMS_HDR_LEN(ipa_sys_params),
1265 QDF_IPA_SYS_PARAMS_HDR_ADDITIONAL_CONST_LEN(
1266 ipa_sys_params),
1267 QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE_VALID(
1268 ipa_sys_params),
1269 QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE(ipa_sys_params),
1270 QDF_IPA_SYS_PARAMS_HDR_LITTLE_ENDIAN(ipa_sys_params),
1271 QDF_IPA_SYS_PARAMS_MODE(ipa_sys_params),
1272 QDF_IPA_SYS_PARAMS_CLIENT(ipa_sys_params),
1273 QDF_IPA_SYS_PARAMS_DESC_FIFO_SZ(ipa_sys_params),
1274 QDF_IPA_SYS_PARAMS_PRIV(ipa_sys_params),
1275 QDF_IPA_SYS_PARAMS_NOTIFY(ipa_sys_params),
1276 QDF_IPA_SYS_PARAMS_SKIP_EP_CFG(ipa_sys_params),
1277 QDF_IPA_SYS_PARAMS_KEEP_IPA_AWAKE(ipa_sys_params));
Yun Parkb187d542016-11-14 18:10:04 -08001278 }
1279}
1280
1281/**
1282 * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct
1283 * @hdd_ipa: HDD IPA struct
1284 *
1285 * Dump entire struct hdd_ipa_iface_context
1286 *
1287 * Return: none
1288 */
1289static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa)
1290{
1291 int i;
1292
1293 /* IPA Interface Contexts */
Yun Park46255682017-10-09 15:56:34 -07001294 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1295 "\n==== IPA Interface Contexts ====\n");
Yun Parkb187d542016-11-14 18:10:04 -08001296
1297 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
1298 struct hdd_ipa_iface_context *iface_context;
1299
1300 iface_context = &hdd_ipa->iface_context[i];
1301
Yun Park46255682017-10-09 15:56:34 -07001302 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
1303 "\niface_context[%d]----\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001304 "\thdd_ipa: %pK\n"
1305 "\tadapter: %pK\n"
1306 "\ttl_context: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001307 "\tcons_client: %d\n"
1308 "\tprod_client: %d\n"
1309 "\tiface_id: %d\n"
1310 "\tsta_id: %d\n"
Jeff Johnson36e74c42017-09-18 08:15:42 -07001311 "\tinterface_lock: %pK\n"
Yun Parkb187d542016-11-14 18:10:04 -08001312 "\tifa_address: 0x%x\n",
1313 i,
1314 iface_context->hdd_ipa,
1315 iface_context->adapter,
1316 iface_context->tl_context,
1317 iface_context->cons_client,
1318 iface_context->prod_client,
1319 iface_context->iface_id,
1320 iface_context->sta_id,
1321 &iface_context->interface_lock,
1322 iface_context->ifa_address);
1323 }
1324}
1325
1326/**
1327 * hdd_ipa_dump_info() - dump HDD IPA struct
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001328 * @hdd_ctx: hdd main context
Yun Parkb187d542016-11-14 18:10:04 -08001329 *
1330 * Dump entire struct hdd_ipa
1331 *
1332 * Return: none
1333 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001334void hdd_ipa_dump_info(struct hdd_context *hdd_ctx)
Yun Parkb187d542016-11-14 18:10:04 -08001335{
1336 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1337
1338 hdd_ipa_dump_hdd_ipa(hdd_ipa);
1339 hdd_ipa_dump_sys_pipe(hdd_ipa);
1340 hdd_ipa_dump_iface_context(hdd_ipa);
1341}
1342
1343/**
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001344 * hdd_ipa_set_tx_flow_info() - To set TX flow info if IPA is
1345 * enabled
1346 *
1347 * This routine is called to set TX flow info if IPA is enabled
1348 *
1349 * Return: None
1350 */
1351void hdd_ipa_set_tx_flow_info(void)
1352{
Jeff Johnson49d45e62017-08-29 14:30:42 -07001353 struct hdd_adapter *adapter;
Jeff Johnsond377dce2017-10-04 10:32:42 -07001354 struct hdd_station_ctx *sta_ctx;
Jeff Johnson87251032017-08-29 13:31:11 -07001355 struct hdd_ap_ctx *hdd_ap_ctx;
Jeff Johnsonca2530c2017-09-30 18:25:40 -07001356 struct hdd_hostapd_state *hostapd_state;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001357 struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1358 struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1359 struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER;
1360 uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0;
1361 const char *p2pMode = "DEV";
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001362 struct hdd_context *hdd_ctx;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001363 cds_context_type *cds_ctx;
1364#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1365 uint8_t targetChannel = 0;
1366 uint8_t preAdapterChannel = 0;
1367 uint8_t channel24;
1368 uint8_t channel5;
Jeff Johnson49d45e62017-08-29 14:30:42 -07001369 struct hdd_adapter *preAdapterContext = NULL;
1370 struct hdd_adapter *adapter2_4 = NULL;
1371 struct hdd_adapter *adapter5 = NULL;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001372 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1373#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1374 struct wlan_objmgr_psoc *psoc;
1375
1376 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1377 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001378 hdd_err("HDD context is NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001379 return;
1380 }
1381
1382 cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
1383 if (!cds_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001384 hdd_err("Invalid CDS Context");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001385 return;
1386 }
1387
1388 psoc = hdd_ctx->hdd_psoc;
Dustin Brown920397d2017-12-13 16:27:50 -08001389
1390 hdd_for_each_adapter(hdd_ctx, adapter) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001391 switch (adapter->device_mode) {
1392 case QDF_STA_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001393 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001394 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001395 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001396 staChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001397 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001398 qdf_copy_macaddr(&staBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001399 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001400#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1401 targetChannel = staChannel;
1402#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1403 }
1404 break;
1405 case QDF_P2P_CLIENT_MODE:
Jeff Johnsond377dce2017-10-04 10:32:42 -07001406 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001407 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -07001408 sta_ctx->conn_info.connState) {
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001409 p2pChannel =
Jeff Johnsond377dce2017-10-04 10:32:42 -07001410 sta_ctx->conn_info.operationChannel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001411 qdf_copy_macaddr(&p2pBssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -07001412 &sta_ctx->conn_info.bssId);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001413 p2pMode = "CLI";
1414#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1415 targetChannel = p2pChannel;
1416#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1417 }
1418 break;
1419 case QDF_P2P_GO_MODE:
1420 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1421 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001422 if (hostapd_state->bss_state == BSS_START
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001423 && hostapd_state->qdf_status ==
1424 QDF_STATUS_SUCCESS) {
Jeff Johnson01206862017-10-27 20:55:59 -07001425 p2pChannel = hdd_ap_ctx->operating_channel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001426 qdf_copy_macaddr(&p2pBssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001427 &adapter->mac_addr);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001428#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1429 targetChannel = p2pChannel;
1430#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1431 }
1432 p2pMode = "GO";
1433 break;
1434 case QDF_SAP_MODE:
1435 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
1436 hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter);
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001437 if (hostapd_state->bss_state == BSS_START
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001438 && hostapd_state->qdf_status ==
1439 QDF_STATUS_SUCCESS) {
Jeff Johnson01206862017-10-27 20:55:59 -07001440 apChannel = hdd_ap_ctx->operating_channel;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001441 qdf_copy_macaddr(&apBssid,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001442 &adapter->mac_addr);
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001443#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1444 targetChannel = apChannel;
1445#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
1446 }
1447 break;
1448 case QDF_IBSS_MODE:
1449 default:
1450 break;
1451 }
1452#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
1453 if (targetChannel) {
1454 /*
1455 * This is first adapter detected as active
1456 * set as default for none concurrency case
1457 */
1458 if (!preAdapterChannel) {
1459 /* If IPA UC data path is enabled,
1460 * target should reserve extra tx descriptors
1461 * for IPA data path.
1462 * Then host data path should allow less TX
1463 * packet pumping in case IPA
1464 * data path enabled
1465 */
1466 if (hdd_ipa_uc_is_enabled(hdd_ctx) &&
1467 (QDF_SAP_MODE == adapter->device_mode)) {
1468 adapter->tx_flow_low_watermark =
1469 hdd_ctx->config->TxFlowLowWaterMark +
1470 WLAN_TFC_IPAUC_TX_DESC_RESERVE;
1471 } else {
1472 adapter->tx_flow_low_watermark =
1473 hdd_ctx->config->
1474 TxFlowLowWaterMark;
1475 }
1476 adapter->tx_flow_high_watermark_offset =
1477 hdd_ctx->config->TxFlowHighWaterMarkOffset;
1478 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001479 adapter->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001480 hdd_ctx->config->TxFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001481 hdd_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001482 adapter->device_mode,
1483 targetChannel,
1484 adapter->tx_flow_low_watermark,
1485 adapter->tx_flow_low_watermark +
1486 adapter->tx_flow_high_watermark_offset,
1487 hdd_ctx->config->TxFlowMaxQueueDepth);
1488 preAdapterChannel = targetChannel;
1489 preAdapterContext = adapter;
1490 } else {
1491 /*
1492 * SCC, disable TX flow control for both
1493 * SCC each adapter cannot reserve dedicated
1494 * channel resource, as a result, if any adapter
1495 * blocked OS Q by flow control,
1496 * blocked adapter will lost chance to recover
1497 */
1498 if (preAdapterChannel == targetChannel) {
1499 /* Current adapter */
1500 adapter->tx_flow_low_watermark = 0;
1501 adapter->
1502 tx_flow_high_watermark_offset = 0;
1503 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001504 adapter->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001505 hdd_ctx->config->
1506 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001507 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001508 hdd_device_mode_to_string(
1509 adapter->device_mode),
1510 adapter->device_mode,
1511 targetChannel,
1512 adapter->tx_flow_low_watermark,
1513 adapter->tx_flow_low_watermark +
1514 adapter->
1515 tx_flow_high_watermark_offset,
1516 hdd_ctx->config->
1517 TxHbwFlowMaxQueueDepth);
1518
1519 if (!preAdapterContext) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001520 hdd_err("SCC: Previous adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001521 continue;
1522 }
1523
1524 /* Previous adapter */
1525 preAdapterContext->
1526 tx_flow_low_watermark = 0;
1527 preAdapterContext->
1528 tx_flow_high_watermark_offset = 0;
1529 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001530 preAdapterContext->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001531 hdd_ctx->config->
1532 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001533 hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001534 hdd_device_mode_to_string(
1535 preAdapterContext->device_mode
1536 ),
1537 preAdapterContext->device_mode,
1538 targetChannel,
1539 preAdapterContext->
1540 tx_flow_low_watermark,
1541 preAdapterContext->
1542 tx_flow_low_watermark +
1543 preAdapterContext->
1544 tx_flow_high_watermark_offset,
1545 hdd_ctx->config->
1546 TxHbwFlowMaxQueueDepth);
1547 }
1548 /*
1549 * MCC, each adapter will have dedicated
1550 * resource
1551 */
1552 else {
1553 /* current channel is 2.4 */
1554 if (targetChannel <=
1555 WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) {
1556 channel24 = targetChannel;
1557 channel5 = preAdapterChannel;
1558 adapter2_4 = adapter;
1559 adapter5 = preAdapterContext;
1560 } else {
1561 /* Current channel is 5 */
1562 channel24 = preAdapterChannel;
1563 channel5 = targetChannel;
1564 adapter2_4 = preAdapterContext;
1565 adapter5 = adapter;
1566 }
1567
1568 if (!adapter5) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001569 hdd_err("MCC: 5GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001570 continue;
1571 }
1572 adapter5->tx_flow_low_watermark =
1573 hdd_ctx->config->
1574 TxHbwFlowLowWaterMark;
1575 adapter5->
1576 tx_flow_high_watermark_offset =
1577 hdd_ctx->config->
1578 TxHbwFlowHighWaterMarkOffset;
1579 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001580 adapter5->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001581 hdd_ctx->config->
1582 TxHbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001583 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001584 hdd_device_mode_to_string(
1585 adapter5->device_mode),
1586 adapter5->device_mode,
1587 channel5,
1588 adapter5->tx_flow_low_watermark,
1589 adapter5->
1590 tx_flow_low_watermark +
1591 adapter5->
1592 tx_flow_high_watermark_offset,
1593 hdd_ctx->config->
1594 TxHbwFlowMaxQueueDepth);
1595
1596 if (!adapter2_4) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001597 hdd_err("MCC: 2.4GHz adapter context NULL");
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001598 continue;
1599 }
1600 adapter2_4->tx_flow_low_watermark =
1601 hdd_ctx->config->
1602 TxLbwFlowLowWaterMark;
1603 adapter2_4->
1604 tx_flow_high_watermark_offset =
1605 hdd_ctx->config->
1606 TxLbwFlowHighWaterMarkOffset;
1607 cdp_fc_ll_set_tx_pause_q_depth(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001608 adapter2_4->session_id,
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001609 hdd_ctx->config->
1610 TxLbwFlowMaxQueueDepth);
Jeff Johnson6867ec32017-09-29 20:30:20 -07001611 hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d",
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001612 hdd_device_mode_to_string(
1613 adapter2_4->device_mode),
1614 adapter2_4->device_mode,
1615 channel24,
1616 adapter2_4->
1617 tx_flow_low_watermark,
1618 adapter2_4->
1619 tx_flow_low_watermark +
1620 adapter2_4->
1621 tx_flow_high_watermark_offset,
1622 hdd_ctx->config->
1623 TxLbwFlowMaxQueueDepth);
1624
1625 }
1626 }
1627 }
1628 targetChannel = 0;
1629#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001630 }
Dustin Brown920397d2017-12-13 16:27:50 -08001631
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08001632 hdd_ctx->mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
1633}
1634
1635/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001636 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001637 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001638 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1639 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001640 *
1641 * Return: true if IPA is enabled, false otherwise
1642 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001643static void __hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001644 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1645{
1646 struct hdd_ipa_priv *hdd_ipa;
1647
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001648 *ipa_tx_diff = 0;
1649 *ipa_rx_diff = 0;
1650
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001651 if (wlan_hdd_validate_context(hdd_ctx))
1652 return;
1653
1654 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1655
1656 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1657 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658 return;
1659 }
1660
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301661 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001662 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1663 (false == hdd_ipa->resource_loading)) {
1664 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1665 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301667 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668}
1669
1670/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001671 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1672 * @hdd_ctx: Global HDD context
1673 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1674 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1675 *
1676 * Return: true if IPA is enabled, false otherwise
1677 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001678void hdd_ipa_uc_stat_query(struct hdd_context *hdd_ctx,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001679 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1680{
1681 cds_ssr_protect(__func__);
1682 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1683 cds_ssr_unprotect(__func__);
1684}
1685
1686/**
1687 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 * @adapter: network adapter
1689 * @reason: STAT REQ Reason
1690 *
1691 * Return: None
1692 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07001693static void __hdd_ipa_uc_stat_request(struct hdd_adapter *adapter,
1694 uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001696 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 struct hdd_ipa_priv *hdd_ipa;
1698
Yun Park637d6482016-10-05 10:51:33 -07001699 if (!adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701
Jeff Johnson399c6272017-08-30 10:51:00 -07001702 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001703
1704 if (wlan_hdd_validate_context(hdd_ctx))
1705 return;
1706
1707 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1708 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1709 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001710 return;
1711 }
1712
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301713 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001714 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1715 (false == hdd_ipa->resource_loading)) {
1716 hdd_ipa->stat_req_reason = reason;
Yun Park637d6482016-10-05 10:51:33 -07001717 qdf_mutex_release(&hdd_ipa->ipa_lock);
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001718 sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07001719 adapter->session_id,
Sandeep Puligillaf587adf2017-04-27 19:53:21 -07001720 WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721 0, VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001722 } else {
1723 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001724 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725}
1726
1727/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001728 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1729 * @adapter: network adapter
1730 * @reason: STAT REQ Reason
1731 *
1732 * Return: None
1733 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001734void hdd_ipa_uc_stat_request(struct hdd_adapter *adapter, uint8_t reason)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001735{
1736 cds_ssr_protect(__func__);
1737 __hdd_ipa_uc_stat_request(adapter, reason);
1738 cds_ssr_unprotect(__func__);
1739}
1740
Yun Park637d6482016-10-05 10:51:33 -07001741#ifdef FEATURE_METERING
1742/**
1743 * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
1744 * @adapter: network adapter
1745 * @reset_stats: reset stat countis after response
1746 *
1747 * Return: None
1748 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001749void hdd_ipa_uc_sharing_stats_request(struct hdd_adapter *adapter,
Yun Park637d6482016-10-05 10:51:33 -07001750 uint8_t reset_stats)
1751{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001752 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001753 struct hdd_ipa_priv *hdd_ipa;
1754
1755 if (!adapter)
1756 return;
1757
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001758 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1759 hdd_ipa = hdd_ctx->hdd_ipa;
1760 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1761 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001762 return;
1763 }
1764
1765 HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats);
1766 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001767 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001768 qdf_mutex_release(&hdd_ipa->ipa_lock);
1769 wma_cli_set_command(
Jeff Johnson1b780e42017-10-31 14:11:45 -07001770 (int)adapter->session_id,
Yun Park637d6482016-10-05 10:51:33 -07001771 (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
1772 reset_stats, VDEV_CMD);
1773 } else {
1774 qdf_mutex_release(&hdd_ipa->ipa_lock);
1775 }
1776}
1777
1778/**
1779 * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
1780 * @adapter: network adapter
1781 * @set_quota: when 1, FW starts quota monitoring
1782 * @quota_bytes: quota limit in bytes
1783 *
1784 * Return: None
1785 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07001786void hdd_ipa_uc_set_quota(struct hdd_adapter *adapter, uint8_t set_quota,
Yun Park637d6482016-10-05 10:51:33 -07001787 uint64_t quota_bytes)
1788{
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001789 struct hdd_context *hdd_ctx;
Yun Park637d6482016-10-05 10:51:33 -07001790 struct hdd_ipa_priv *hdd_ipa;
1791
1792 if (!adapter)
1793 return;
1794
Jeff Johnson2c4a93f2017-09-03 08:51:14 -07001795 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1796 hdd_ipa = hdd_ctx->hdd_ipa;
1797 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1798 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Yun Park637d6482016-10-05 10:51:33 -07001799 return;
1800 }
1801
1802 HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
1803 set_quota, quota_bytes);
1804
1805 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Park3374a4b2016-12-15 16:52:15 -08001806 if (false == hdd_ipa->resource_loading) {
Yun Park637d6482016-10-05 10:51:33 -07001807 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park327e7812017-02-14 15:18:10 -08001808 wma_cli_set2_command(
Jeff Johnson1b780e42017-10-31 14:11:45 -07001809 (int)adapter->session_id,
Yun Park637d6482016-10-05 10:51:33 -07001810 (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
Yun Park327e7812017-02-14 15:18:10 -08001811 (set_quota ? quota_bytes&0xffffffff : 0),
1812 (set_quota ? quota_bytes>>32 : 0),
1813 VDEV_CMD);
Yun Park637d6482016-10-05 10:51:33 -07001814 } else {
1815 qdf_mutex_release(&hdd_ipa->ipa_lock);
1816 }
1817}
1818#endif
1819
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001820/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1822 * @hdd_ipa: Global HDD IPA context
1823 * @sta_add: Should station be added
1824 * @sta_id: ID of the station being queried
1825 *
1826 * Return: true if the station was found
1827 */
1828static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1829 bool sta_add, uint8_t sta_id)
1830{
1831 bool sta_found = false;
1832 uint8_t idx;
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07001833
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001834 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1835 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1836 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1837 sta_found = true;
1838 break;
1839 }
1840 }
1841 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301842 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001843 "STA ID %d already exist, cannot add", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844 return sta_found;
1845 }
1846 if (sta_add) {
1847 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1848 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1849 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1850 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1851 return sta_found;
1852 }
1853 }
1854 }
1855 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301856 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001857 "STA ID %d does not exist, cannot delete", sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858 return sta_found;
1859 }
1860 if (!sta_add) {
1861 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1862 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1863 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1864 hdd_ipa->assoc_stas_map[idx].is_reserved =
1865 false;
1866 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1867 return sta_found;
1868 }
1869 }
1870 }
1871 return sta_found;
1872}
1873
1874/**
1875 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1876 * @hdd_ipa: Global HDD IPA context
1877 *
1878 * Return: 0 on success, negative errno if error
1879 */
1880static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1881{
Yun Parkfec73dc2017-09-06 10:40:07 -07001882 int result = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07001883 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07001884 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885
Yun Park199c2ed2017-10-02 11:24:22 -07001886 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
1887
1888 if (!hdd_ipa->ipa_pipes_down) {
1889 /*
1890 * This shouldn't happen :
1891 * IPA WDI Pipes are already activated
1892 */
1893 WARN_ON(1);
1894 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
1895 "IPA WDI Pipes are already activated");
1896 goto end;
1897 }
Yun Parkfec73dc2017-09-06 10:40:07 -07001898
Yun Parkb4f591d2017-03-29 15:51:01 -07001899 result = cdp_ipa_enable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301901 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001902 "Enable PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001903 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001904 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001905
Yun Park777d7242017-03-30 15:38:33 -07001906 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Leo Change3e49442015-10-26 20:07:13 -07001907 hdd_ipa->ipa_pipes_down = false;
Yun Parkb4f591d2017-03-29 15:51:01 -07001908
1909 cdp_ipa_enable_autonomy(soc, (struct cdp_pdev *)pdev);
1910
Yun Parkfec73dc2017-09-06 10:40:07 -07001911end:
Yun Park199c2ed2017-10-02 11:24:22 -07001912 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07001913 hdd_ipa->ipa_pipes_down);
Yun Park199c2ed2017-10-02 11:24:22 -07001914
Yun Parkfec73dc2017-09-06 10:40:07 -07001915 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001916}
1917
1918/**
1919 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1920 * @hdd_ipa: Global HDD IPA context
1921 *
1922 * Return: 0 on success, negative errno if error
1923 */
1924static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1925{
Yun Parkb4f591d2017-03-29 15:51:01 -07001926 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1927 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkfec73dc2017-09-06 10:40:07 -07001928 int result = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001929
Yun Park199c2ed2017-10-02 11:24:22 -07001930 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
1931
1932 if (hdd_ipa->ipa_pipes_down) {
1933 /*
1934 * This shouldn't happen :
1935 * IPA WDI Pipes are already deactivated
1936 */
1937 WARN_ON(1);
1938 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
1939 "IPA WDI Pipes are already deactivated");
1940 goto end;
1941 }
Leo Change3e49442015-10-26 20:07:13 -07001942
Yun Parkb4f591d2017-03-29 15:51:01 -07001943 cdp_ipa_disable_autonomy(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001944
Yun Parkb4f591d2017-03-29 15:51:01 -07001945 result = cdp_ipa_disable_pipes(soc, (struct cdp_pdev *)pdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301947 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001948 "Disable WDI PIPE fail, code %d", result);
Yun Parkfec73dc2017-09-06 10:40:07 -07001949 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950 }
1951
Yun Parkfec73dc2017-09-06 10:40:07 -07001952 hdd_ipa->ipa_pipes_down = true;
1953
1954end:
Yun Park199c2ed2017-10-02 11:24:22 -07001955 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: ipa_pipes_down=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07001956 hdd_ipa->ipa_pipes_down);
1957 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958}
1959
1960/**
1961 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1962 * @hdd_ipa: Global HDD IPA context
1963 *
1964 * Return: 0 on success, negative errno if error
1965 */
1966static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1967{
Jeff Johnsondd595cb2017-08-28 11:58:09 -07001968 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07001969
Yun Park199c2ed2017-10-02 11:24:22 -07001970 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07001971
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972 hdd_ipa->activated_fw_pipe = 0;
1973 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001974
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001975 /* If RM feature enabled
1976 * Request PROD Resource first
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07001977 * PROD resource may return sync or async manners
1978 */
Yun Parkb4f591d2017-03-29 15:51:01 -07001979 if (hdd_ipa_is_rm_enabled(hdd_ctx)) {
Yun Park4cab6ee2015-10-27 11:43:40 -07001980 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1981 /* RM PROD request sync return
1982 * enable pipe immediately
1983 */
1984 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301985 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07001986 "IPA WDI Pipe activation failed");
Yun Park4cab6ee2015-10-27 11:43:40 -07001987 hdd_ipa->resource_loading = false;
1988 return -EBUSY;
1989 }
Sravan Kumar Kairamc76f28a2017-07-25 19:03:40 +05301990 } else {
1991 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park199c2ed2017-10-02 11:24:22 -07001992 "IPA WDI Pipe activation deferred");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 }
1994 } else {
1995 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001996 * Just enabled all the PIPEs
1997 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301999 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07002000 "IPA WDI Pipe activation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002001 hdd_ipa->resource_loading = false;
2002 return -EBUSY;
2003 }
2004 hdd_ipa->resource_loading = false;
2005 }
Yun Park4cab6ee2015-10-27 11:43:40 -07002006
Yun Park199c2ed2017-10-02 11:24:22 -07002007 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002008 return 0;
2009}
2010
2011/**
2012 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
2013 * @hdd_ipa: Global HDD IPA context
2014 *
2015 * Return: None
2016 */
2017static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
2018{
Leo Changfdb45c32016-10-28 11:09:23 -07002019 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkb4f591d2017-03-29 15:51:01 -07002020 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021
Yun Park199c2ed2017-10-02 11:24:22 -07002022 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07002023
Yun Parkb4f591d2017-03-29 15:51:01 -07002024 if (!pdev) {
Yun Park7c4f31b2016-11-30 10:09:21 -08002025 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
2026 QDF_ASSERT(0);
2027 return;
2028 }
2029
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002030 hdd_ipa->resource_unloading = true;
Yun Park777d7242017-03-30 15:38:33 -07002031 INIT_COMPLETION(hdd_ipa->ipa_resource_comp);
Yun Parkb4f591d2017-03-29 15:51:01 -07002032 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW RX PIPE");
2033 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, false);
2034 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW TX PIPE");
2035 cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, true);
Yun Parkfec73dc2017-09-06 10:40:07 -07002036
Yun Park199c2ed2017-10-02 11:24:22 -07002037 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: IPA WDI Pipes deactivated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038}
2039
2040/**
2041 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
2042 * @context: User context registered with TL (the IPA Global context is
2043 * registered
2044 * @rxpkt: Packet containing the notification
2045 * @staid: ID of the station associated with the packet
2046 *
2047 * Return: None
2048 */
2049static void
Yun Park6c86a662017-10-05 16:09:15 -07002050hdd_ipa_uc_rm_notify_handler(void *context, qdf_ipa_rm_event_t event)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051{
2052 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302053 QDF_STATUS status = QDF_STATUS_SUCCESS;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002054 struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055
2056 /*
2057 * When SSR is going on or driver is unloading, just return.
2058 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002059 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302060 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002061 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062
Yun Parkb4f591d2017-03-29 15:51:01 -07002063 if (!hdd_ipa_is_rm_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002064 return;
2065
Yun Park46255682017-10-09 15:56:34 -07002066 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event code %d",
2067 event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068
2069 switch (event) {
2070 case IPA_RM_RESOURCE_GRANTED:
2071 /* Differed RM Granted */
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302072 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002073 if ((false == hdd_ipa->resource_unloading) &&
2074 (!hdd_ipa->activated_fw_pipe)) {
2075 hdd_ipa_uc_enable_pipes(hdd_ipa);
2076 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302077 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002078 break;
2079
2080 case IPA_RM_RESOURCE_RELEASED:
2081 /* Differed RM Released */
2082 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083 break;
2084
2085 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302086 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07002087 "invalid event code %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002088 break;
2089 }
2090}
2091
2092/**
2093 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
2094 * @hdd_ipa: Global HDD IPA context
2095 * @event: IPA resource manager event to be deferred
2096 *
2097 * This function is called when a resource manager event is received
2098 * from firmware in interrupt context. This function will defer the
2099 * handling to the OL RX thread
2100 *
2101 * Return: None
2102 */
2103static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
2104{
Yun Park6c86a662017-10-05 16:09:15 -07002105 qdf_ipa_rm_event_t event;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002106 struct uc_rm_work_struct *uc_rm_work = container_of(work,
2107 struct uc_rm_work_struct, work);
2108 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
2109 struct hdd_ipa_priv, uc_rm_work);
2110
2111 cds_ssr_protect(__func__);
2112 event = uc_rm_work->event;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002113 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07002114 "posted event %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002115
2116 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
2117 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002118}
2119
2120/**
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002121 * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
Yun Parkb4f591d2017-03-29 15:51:01 -07002122 * @hdd_ipa: hdd ipa local context
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002123 *
2124 * Will handle IPA UC image loaded indication comes from IPA kernel
2125 *
2126 * Return: None
2127 */
Yun Parkb4f591d2017-03-29 15:51:01 -07002128static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *hdd_ipa)
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002129{
Yun Parkb4f591d2017-03-29 15:51:01 -07002130 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2131 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002132 struct hdd_context *hdd_ctx;
Yun Parkb4f591d2017-03-29 15:51:01 -07002133 QDF_STATUS status;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002134
Yun Park46255682017-10-09 15:56:34 -07002135 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC READY");
Yun Parkb4f591d2017-03-29 15:51:01 -07002136 if (true == hdd_ipa->uc_loaded) {
Yun Park46255682017-10-09 15:56:34 -07002137 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "UC already loaded");
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002138 return;
2139 }
2140
Yun Parkb4f591d2017-03-29 15:51:01 -07002141 hdd_ctx = hdd_ipa->hdd_ctx;
2142 hdd_ipa->uc_loaded = true;
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002143
Yun Parkb4f591d2017-03-29 15:51:01 -07002144 /* Connect pipe */
2145 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
2146 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
2147 hdd_ipa_wdi_meter_notifier_cb,
2148 hdd_ctx->config->IpaDescSize,
2149 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
2150 &hdd_ipa->tx_pipe_handle,
2151 &hdd_ipa->rx_pipe_handle);
2152 if (status) {
2153 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2154 "Failure to setup IPA pipes (status=%d)",
2155 status);
2156 return;
2157 }
2158
2159 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002160
2161 /* If already any STA connected, enable IPA/FW PIPEs */
Yun Parkb4f591d2017-03-29 15:51:01 -07002162 if (hdd_ipa->sap_num_connected_sta) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08002163 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002164 "Client already connected, enable IPA/FW PIPEs");
Yun Parkb4f591d2017-03-29 15:51:01 -07002165 hdd_ipa_uc_handle_first_con(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002166 }
2167}
2168
2169/**
Yun Park637d6482016-10-05 10:51:33 -07002170 * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
2171 * @hdd_ctx: Global HDD context
2172 * @op_msg: operation message received from firmware
2173 *
2174 * Return: QDF_STATUS enumeration
2175 */
2176#ifdef FEATURE_METERING
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002177static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002178 struct op_msg_type *op_msg)
2179{
2180 struct op_msg_type *msg = op_msg;
2181 struct ipa_uc_sharing_stats *uc_sharing_stats;
2182 struct ipa_uc_quota_rsp *uc_quota_rsp;
2183 struct ipa_uc_quota_ind *uc_quota_ind;
2184 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002185 struct hdd_adapter *adapter;
Yun Park637d6482016-10-05 10:51:33 -07002186
2187 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2188
2189 if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
2190 /* fill-up ipa_uc_sharing_stats structure from FW */
2191 uc_sharing_stats = (struct ipa_uc_sharing_stats *)
2192 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2193
2194 memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
2195 sizeof(struct ipa_uc_sharing_stats));
2196
2197 complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
2198
2199 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2200 "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2201 "HDD_IPA_UC_OPCODE_SHARING_STATS",
2202 hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
2203 hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
2204 hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
2205 hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
2206 hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
2207 hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
2208 hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
2209 hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
2210 } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
2211 /* received set quota response */
2212 uc_quota_rsp = (struct ipa_uc_quota_rsp *)
2213 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2214
2215 memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
2216 sizeof(struct ipa_uc_quota_rsp));
2217
2218 complete(&hdd_ipa->ipa_uc_set_quota_comp);
2219 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2220 "%s: success=%d, quota_bytes=%llu",
2221 "HDD_IPA_UC_OPCODE_QUOTA_RSP",
2222 hdd_ipa->ipa_quota_rsp.success,
2223 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
2224 hdd_ipa->ipa_quota_rsp.quota_lo);
2225 } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
2226 /* hit quota limit */
2227 uc_quota_ind = (struct ipa_uc_quota_ind *)
2228 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2229
2230 hdd_ipa->ipa_quota_ind.quota_bytes =
2231 uc_quota_ind->quota_bytes;
2232
2233 /* send quota exceeded indication to IPA */
2234 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2235 "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
2236 hdd_ipa->ipa_quota_ind.quota_bytes);
2237
2238 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2239 if (adapter)
2240 ipa_broadcast_wdi_quota_reach_ind(
2241 adapter->dev->ifindex,
2242 uc_quota_ind->quota_bytes);
2243 else
2244 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2245 "Failed quota_reach_ind: NULL adapter");
2246 } else {
2247 return QDF_STATUS_E_INVAL;
2248 }
2249
2250 return QDF_STATUS_SUCCESS;
2251}
2252#else
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002253static QDF_STATUS hdd_ipa_uc_op_metering(struct hdd_context *hdd_ctx,
Yun Park637d6482016-10-05 10:51:33 -07002254 struct op_msg_type *op_msg)
2255{
2256 return QDF_STATUS_E_INVAL;
2257}
2258#endif
2259
Yun Park657c7d72017-06-07 15:44:59 -07002260#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0))
2261/* older versions had a typo */
2262#define num_bam_int_in_non_running_state num_bam_int_in_non_runnning_state
2263#endif
2264
Yun Park637d6482016-10-05 10:51:33 -07002265/**
Yun Park46255682017-10-09 15:56:34 -07002266 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
2267 * @event: IPA WLAN event to be converted to a string
2268 *
2269 * Return: ASCII string representing the IPA WLAN event
2270 */
Yun Park6c86a662017-10-05 16:09:15 -07002271static inline char *hdd_ipa_wlan_event_to_str(qdf_ipa_wlan_event_t event)
Yun Park46255682017-10-09 15:56:34 -07002272{
2273 switch (event) {
2274 CASE_RETURN_STRING(WLAN_CLIENT_CONNECT);
2275 CASE_RETURN_STRING(WLAN_CLIENT_DISCONNECT);
2276 CASE_RETURN_STRING(WLAN_CLIENT_POWER_SAVE_MODE);
2277 CASE_RETURN_STRING(WLAN_CLIENT_NORMAL_MODE);
2278 CASE_RETURN_STRING(SW_ROUTING_ENABLE);
2279 CASE_RETURN_STRING(SW_ROUTING_DISABLE);
2280 CASE_RETURN_STRING(WLAN_AP_CONNECT);
2281 CASE_RETURN_STRING(WLAN_AP_DISCONNECT);
2282 CASE_RETURN_STRING(WLAN_STA_CONNECT);
2283 CASE_RETURN_STRING(WLAN_STA_DISCONNECT);
2284 CASE_RETURN_STRING(WLAN_CLIENT_CONNECT_EX);
2285 default:
2286 return "UNKNOWN";
2287 }
2288}
2289
2290/**
2291 * hdd_ipa_print_session_info - Print IPA session info
2292 * @hdd_ipa: HDD IPA local context
2293 *
2294 * Return: None
2295 */
2296static void hdd_ipa_print_session_info(struct hdd_ipa_priv *hdd_ipa)
2297{
2298 uint8_t session_id;
2299 int device_mode;
2300 struct ipa_uc_pending_event *event = NULL, *next = NULL;
2301 struct hdd_ipa_iface_context *iface_context = NULL;
2302 int i;
2303
2304 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2305 "\n==== IPA SESSION INFO ====\n"
2306 "NUM IFACE: %d\n"
2307 "RM STATE: %d\n"
2308 "ACTIVATED FW PIPE: %d\n"
2309 "SAP NUM STAs: %d\n"
2310 "STA CONNECTED: %d\n"
2311 "CONCURRENT MODE: %s\n"
2312 "RSC LOADING: %d\n"
2313 "RSC UNLOADING: %d\n"
2314 "PENDING CONS REQ: %d\n"
2315 "IPA PIPES DOWN: %d\n"
2316 "IPA UC LOADED: %d\n"
2317 "IPA WDI ENABLED: %d\n"
2318 "NUM SEND MSG: %d\n"
2319 "NUM FREE MSG: %d\n",
2320 hdd_ipa->num_iface,
2321 hdd_ipa->rm_state,
2322 hdd_ipa->activated_fw_pipe,
2323 hdd_ipa->sap_num_connected_sta,
2324 hdd_ipa->sta_connected,
2325 (hdd_ipa->hdd_ctx->mcc_mode ? "MCC" : "SCC"),
2326 hdd_ipa->resource_loading,
2327 hdd_ipa->resource_unloading,
2328 hdd_ipa->pending_cons_req,
2329 hdd_ipa->ipa_pipes_down,
2330 hdd_ipa->uc_loaded,
2331 hdd_ipa->wdi_enabled,
2332 (unsigned int)hdd_ipa->stats.num_send_msg,
2333 (unsigned int)hdd_ipa->stats.num_free_msg);
2334
2335 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2336 iface_context = &hdd_ipa->iface_context[i];
2337 if (!iface_context || !iface_context->adapter)
2338 continue;
2339
Jeff Johnson1b780e42017-10-31 14:11:45 -07002340 session_id = iface_context->adapter->session_id;
Yun Park46255682017-10-09 15:56:34 -07002341 if (session_id >= CSR_ROAM_SESSION_MAX)
2342 continue;
2343
2344 device_mode = iface_context->adapter->device_mode;
2345 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2346 "\nIFACE[%d]: session:%d, sta_id:%d, mode:%s, offload:%d",
2347 i, session_id,
2348 iface_context->sta_id,
2349 hdd_device_mode_to_string(device_mode),
2350 hdd_ipa->vdev_offload_enabled[session_id]);
2351 }
2352
2353 for (i = 0; i < IPA_WLAN_EVENT_MAX; i++)
2354 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2355 "\nEVENT[%d]=%d",
2356 i, hdd_ipa->stats.event[i]);
2357
2358 i = 0;
2359 qdf_list_peek_front(&hdd_ipa->pending_event,
2360 (qdf_list_node_t **)&event);
2361 while (event != NULL) {
2362 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2363 "\nPENDING EVENT[%d]: DEV:%s, EVT:%s, sta_id:%d, MAC:%pM",
2364 i, event->adapter->dev->name,
2365 hdd_ipa_wlan_event_to_str(event->type),
2366 event->sta_id, event->mac_addr);
2367
2368 qdf_list_peek_next(&hdd_ipa->pending_event,
2369 (qdf_list_node_t *)event, (qdf_list_node_t **)&next);
2370 event = next;
2371 next = NULL;
2372 i++;
2373 }
2374}
2375
2376/**
2377 * hdd_ipa_print_txrx_stats - Print HDD IPA TX/RX stats
2378 * @hdd_ipa: HDD IPA local context
2379 *
2380 * Return: None
2381 */
2382static void hdd_ipa_print_txrx_stats(struct hdd_ipa_priv *hdd_ipa)
2383{
2384 int i;
2385 struct hdd_ipa_iface_context *iface_context = NULL;
2386
2387 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2388 "\n==== HDD IPA TX/RX STATS ====\n"
2389 "NUM RM GRANT: %llu\n"
2390 "NUM RM RELEASE: %llu\n"
2391 "NUM RM GRANT IMM: %llu\n"
2392 "NUM CONS PERF REQ: %llu\n"
2393 "NUM PROD PERF REQ: %llu\n"
2394 "NUM RX DROP: %llu\n"
2395 "NUM EXCP PKT: %llu\n"
2396 "NUM TX FWD OK: %llu\n"
2397 "NUM TX FWD ERR: %llu\n"
2398 "NUM TX DESC Q CNT: %llu\n"
2399 "NUM TX DESC ERROR: %llu\n"
2400 "NUM TX COMP CNT: %llu\n"
2401 "NUM TX QUEUED: %llu\n"
2402 "NUM TX DEQUEUED: %llu\n"
2403 "NUM MAX PM QUEUE: %llu\n"
2404 "TX REF CNT: %d\n"
2405 "SUSPENDED: %d\n"
2406 "PEND DESC HEAD: %pK\n"
2407 "TX DESC LIST: %pK\n"
2408 "FREE TX DESC HEAD: %pK\n",
2409 hdd_ipa->stats.num_rm_grant,
2410 hdd_ipa->stats.num_rm_release,
2411 hdd_ipa->stats.num_rm_grant_imm,
2412 hdd_ipa->stats.num_cons_perf_req,
2413 hdd_ipa->stats.num_prod_perf_req,
2414 hdd_ipa->stats.num_rx_drop,
2415 hdd_ipa->stats.num_rx_excep,
2416 hdd_ipa->stats.num_tx_fwd_ok,
2417 hdd_ipa->stats.num_tx_fwd_err,
2418 hdd_ipa->stats.num_tx_desc_q_cnt,
2419 hdd_ipa->stats.num_tx_desc_error,
2420 hdd_ipa->stats.num_tx_comp_cnt,
2421 hdd_ipa->stats.num_tx_queued,
2422 hdd_ipa->stats.num_tx_dequeued,
2423 hdd_ipa->stats.num_max_pm_queue,
2424 hdd_ipa->tx_ref_cnt.counter,
2425 hdd_ipa->suspended,
2426 &hdd_ipa->pend_desc_head,
2427 hdd_ipa->tx_desc_list,
2428 &hdd_ipa->free_tx_desc_head);
2429
2430 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
2431 iface_context = &hdd_ipa->iface_context[i];
2432 if (!iface_context || !iface_context->adapter)
2433 continue;
2434
2435 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2436 "IFACE[%d]: TX:%llu, TX DROP:%llu, TX ERR:%llu, TX CAC DROP:%llu, RX IPA EXCEP:%llu",
2437 i,
2438 iface_context->stats.num_tx,
2439 iface_context->stats.num_tx_drop,
2440 iface_context->stats.num_tx_err,
2441 iface_context->stats.num_tx_cac_drop,
2442 iface_context->stats.num_rx_ipa_excep);
2443 }
2444}
2445
2446/**
2447 * hdd_ipa_print_fw_wdi_stats - Print WLAN FW WDI stats
2448 * @hdd_ipa: HDD IPA local context
2449 *
2450 * Return: None
2451 */
2452static void hdd_ipa_print_fw_wdi_stats(struct hdd_ipa_priv *hdd_ipa,
2453 struct ipa_uc_fw_stats *uc_fw_stat)
2454{
2455 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2456 "\n==== WLAN FW WDI TX STATS ====\n"
2457 "COMP RING BASE: 0x%x\n"
2458 "COMP RING SIZE: %d\n"
2459 "COMP RING DBELL : 0x%x\n"
2460 "COMP RING DBELL IND VAL : %d\n"
2461 "COMP RING DBELL CACHED VAL : %d\n"
2462 "PKTS ENQ : %d\n"
2463 "PKTS COMP : %d\n"
2464 "IS SUSPEND : %d\n",
2465 uc_fw_stat->tx_comp_ring_base,
2466 uc_fw_stat->tx_comp_ring_size,
2467 uc_fw_stat->tx_comp_ring_dbell_addr,
2468 uc_fw_stat->tx_comp_ring_dbell_ind_val,
2469 uc_fw_stat->tx_comp_ring_dbell_cached_val,
2470 uc_fw_stat->tx_pkts_enqueued,
2471 uc_fw_stat->tx_pkts_completed,
2472 uc_fw_stat->tx_is_suspend);
2473
2474 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2475 "\n==== WLAN FW WDI RX STATS ====\n"
2476 "IND RING BASE: 0x%x\n"
2477 "IND RING SIZE: %d\n"
2478 "IND RING DBELL : 0x%x\n"
2479 "IND RING DBELL IND VAL : %d\n"
2480 "IND RING DBELL CACHED VAL : %d\n"
2481 "RDY IND ADDR : 0x%x\n"
2482 "RDY IND CACHE VAL : %d\n"
2483 "RFIL IND : %d\n"
2484 "NUM PKT INDICAT : %d\n"
2485 "BUF REFIL : %d\n"
2486 "NUM DROP NO SPC : %d\n"
2487 "NUM DROP NO BUF : %d\n"
2488 "IS SUSPND : %d\n",
2489 uc_fw_stat->rx_ind_ring_base,
2490 uc_fw_stat->rx_ind_ring_size,
2491 uc_fw_stat->rx_ind_ring_dbell_addr,
2492 uc_fw_stat->rx_ind_ring_dbell_ind_val,
2493 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
2494 uc_fw_stat->rx_ind_ring_rdidx_addr,
2495 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
2496 uc_fw_stat->rx_refill_idx,
2497 uc_fw_stat->rx_num_pkts_indicated,
2498 uc_fw_stat->rx_buf_refilled,
2499 uc_fw_stat->rx_num_ind_drop_no_space,
2500 uc_fw_stat->rx_num_ind_drop_no_buf,
2501 uc_fw_stat->rx_is_suspend);
2502}
2503
2504/**
2505 * hdd_ipa_print_ipa_wdi_stats - Print IPA WDI stats
2506 * @hdd_ipa: HDD IPA local context
2507 *
2508 * Return: None
2509 */
2510static void hdd_ipa_print_ipa_wdi_stats(struct hdd_ipa_priv *hdd_ipa)
2511{
2512 struct IpaHwStatsWDIInfoData_t ipa_stat;
2513
2514 ipa_get_wdi_stats(&ipa_stat);
2515
2516 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2517 "\n==== IPA WDI TX STATS ====\n"
2518 "NUM PROCD : %d\n"
2519 "CE DBELL : 0x%x\n"
2520 "NUM DBELL FIRED : %d\n"
2521 "COMP RNG FULL : %d\n"
2522 "COMP RNG EMPT : %d\n"
2523 "COMP RNG USE HGH : %d\n"
2524 "COMP RNG USE LOW : %d\n"
2525 "BAM FIFO FULL : %d\n"
2526 "BAM FIFO EMPT : %d\n"
2527 "BAM FIFO USE HGH : %d\n"
2528 "BAM FIFO USE LOW : %d\n"
2529 "NUM DBELL : %d\n"
2530 "NUM UNEXP DBELL : %d\n"
2531 "NUM BAM INT HDL : 0x%x\n"
2532 "NUM BAM INT NON-RUN : 0x%x\n"
2533 "NUM QMB INT HDL : 0x%x\n",
2534 ipa_stat.tx_ch_stats.num_pkts_processed,
2535 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
2536 ipa_stat.tx_ch_stats.num_db_fired,
2537 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
2538 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
2539 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
2540 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
2541 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
2542 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
2543 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
2544 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
2545 ipa_stat.tx_ch_stats.num_db,
2546 ipa_stat.tx_ch_stats.num_unexpected_db,
2547 ipa_stat.tx_ch_stats.num_bam_int_handled,
2548 ipa_stat.tx_ch_stats.
2549#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
2550 num_bam_int_in_non_running_state,
2551#else
2552 num_bam_int_in_non_runnning_state,
2553#endif
2554 ipa_stat.tx_ch_stats.num_qmb_int_handled);
2555
2556 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
2557 "\n==== IPA WDI RX STATS ====\n"
2558 "MAX OST PKT : %d\n"
2559 "NUM PKT PRCSD : %d\n"
2560 "RNG RP : 0x%x\n"
2561 "IND RNG FULL : %d\n"
2562 "IND RNG EMPT : %d\n"
2563 "IND RNG USE HGH : %d\n"
2564 "IND RNG USE LOW : %d\n"
2565 "BAM FIFO FULL : %d\n"
2566 "BAM FIFO EMPT : %d\n"
2567 "BAM FIFO USE HGH : %d\n"
2568 "BAM FIFO USE LOW : %d\n"
2569 "NUM DB : %d\n"
2570 "NUM UNEXP DB : %d\n"
2571 "NUM BAM INT HNDL : 0x%x\n",
2572 ipa_stat.rx_ch_stats.max_outstanding_pkts,
2573 ipa_stat.rx_ch_stats.num_pkts_processed,
2574 ipa_stat.rx_ch_stats.rx_ring_rp_value,
2575 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
2576 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
2577 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
2578 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
2579 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
2580 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
2581 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
2582 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
2583 ipa_stat.rx_ch_stats.num_db,
2584 ipa_stat.rx_ch_stats.num_unexpected_db,
2585 ipa_stat.rx_ch_stats.num_bam_int_handled);
2586}
2587
2588/**
2589 * hdd_ipa_uc_info() - Print IPA uC resource and session information
2590 * @adapter: network adapter
2591 *
2592 * Return: None
2593 */
2594void hdd_ipa_uc_info(struct hdd_context *hdd_ctx)
2595{
2596 struct hdd_ipa_priv *hdd_ipa;
2597
2598 hdd_ipa = hdd_ctx->hdd_ipa;
2599
2600 if (!hdd_ipa) {
2601 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2602 "HDD IPA context is NULL");
2603 return;
2604 }
2605
2606 /* IPA session info */
2607 hdd_ipa_print_session_info(hdd_ipa);
2608}
2609
2610/**
2611 * hdd_ipa_uc_stat() - Print IPA uC stats
2612 * @adapter: network adapter
2613 *
2614 * Return: None
2615 */
2616void hdd_ipa_uc_stat(struct hdd_adapter *adapter)
2617{
2618 struct hdd_context *hdd_ctx;
2619 struct hdd_ipa_priv *hdd_ipa;
2620
2621 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2622 hdd_ipa = hdd_ctx->hdd_ipa;
2623
2624 if (!hdd_ipa) {
2625 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2626 "HDD IPA context is NULL");
2627 return;
2628 }
2629
2630 /* HDD IPA TX/RX stats */
2631 hdd_ipa_print_txrx_stats(hdd_ipa);
2632 /* IPA WDI stats */
2633 hdd_ipa_print_ipa_wdi_stats(hdd_ipa);
2634 /* WLAN FW WDI stats */
2635 hdd_ipa_uc_stat_request(adapter, HDD_IPA_UC_STAT_REASON_DEBUG);
2636}
2637
2638/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002639 * hdd_ipa_uc_op_cb() - IPA uC operation callback
2640 * @op_msg: operation message received from firmware
2641 * @usr_ctxt: user context registered with TL (we register the HDD Global
2642 * context)
2643 *
2644 * Return: None
2645 */
2646static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
2647{
2648 struct op_msg_type *msg = op_msg;
2649 struct ipa_uc_fw_stats *uc_fw_stat;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002650 struct hdd_ipa_priv *hdd_ipa;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002651 struct hdd_context *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302652 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002653
2654 if (!op_msg || !usr_ctxt) {
Yun Park46255682017-10-09 15:56:34 -07002655 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "INVALID ARG");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002656 return;
2657 }
2658
2659 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302660 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07002661 "INVALID OPCODE %d", msg->op_code);
jiadd91a6842017-08-01 14:46:02 +08002662 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002663 return;
2664 }
2665
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002666 hdd_ctx = (struct hdd_context *) usr_ctxt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002667
2668 /*
2669 * When SSR is going on or driver is unloading, just return.
2670 */
2671 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302672 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302673 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002674 return;
2675 }
2676
2677 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
2678
Govind Singhb6a89772016-08-12 11:23:35 +05302679 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park5f0fc232017-02-10 10:34:57 -08002680 "OPCODE=%d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002681
2682 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
2683 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302684 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002685 hdd_ipa->activated_fw_pipe++;
2686 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
2687 hdd_ipa->resource_loading = false;
Yun Park777d7242017-03-30 15:38:33 -07002688 complete(&hdd_ipa->ipa_resource_comp);
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08002689 if (hdd_ipa->wdi_enabled == false) {
2690 hdd_ipa->wdi_enabled = true;
2691 if (hdd_ipa_uc_send_wdi_control_msg(true) == 0)
2692 hdd_ipa_send_mcc_scc_msg(hdd_ctx,
2693 hdd_ctx->mcc_mode);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002694 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002695 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08002696 if (hdd_ipa->pending_cons_req)
2697 ipa_rm_notify_completion(
2698 IPA_RM_RESOURCE_GRANTED,
2699 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08002700 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002701 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302702 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002703 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002704 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302705 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002706 hdd_ipa->activated_fw_pipe--;
2707 if (!hdd_ipa->activated_fw_pipe) {
Yun Park777d7242017-03-30 15:38:33 -07002708 /*
2709 * Async return success from FW
2710 * Disable/suspend all the PIPEs
2711 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002712 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08002713 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2714 ipa_rm_release_resource(
2715 IPA_RM_RESOURCE_WLAN_PROD);
Yun Park5b635012015-12-02 15:05:01 -08002716 hdd_ipa->resource_unloading = false;
Yun Park777d7242017-03-30 15:38:33 -07002717 complete(&hdd_ipa->ipa_resource_comp);
Yun Park5b635012015-12-02 15:05:01 -08002718 hdd_ipa_uc_proc_pending_event(hdd_ipa);
2719 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302721 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07002722 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002723 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002724 uc_fw_stat = (struct ipa_uc_fw_stats *)
Yun Park46255682017-10-09 15:56:34 -07002725 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002726
Yun Park46255682017-10-09 15:56:34 -07002727 /* WLAN FW WDI stats */
2728 hdd_ipa_print_fw_wdi_stats(hdd_ipa, uc_fw_stat);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002729 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
2730 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
2731 /* STATs from FW */
2732 uc_fw_stat = (struct ipa_uc_fw_stats *)
2733 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302734 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002735 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
2736 uc_fw_stat->tx_pkts_completed,
2737 hdd_ipa->ipa_p_tx_packets);
2738 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
2739 (uc_fw_stat->rx_num_ind_drop_no_space +
2740 uc_fw_stat->rx_num_ind_drop_no_buf +
2741 uc_fw_stat->rx_num_pkts_indicated),
2742 hdd_ipa->ipa_p_rx_packets);
2743
2744 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2745 hdd_ipa->ipa_p_rx_packets =
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);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302749 qdf_mutex_release(&hdd_ipa->ipa_lock);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08002750 } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) {
2751 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
2752 hdd_ipa_uc_loaded_handler(hdd_ipa);
2753 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park637d6482016-10-05 10:51:33 -07002754 } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
2755 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
2756 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002757 }
Yun Park8957d802017-01-25 12:27:29 -08002758
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302759 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002760}
2761
2762
2763/**
2764 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
2765 * @adapter: device adapter instance
2766 * @offload_type: MCC or SCC
2767 * @enable: TX offload enable or disable
2768 *
2769 * Return: none
2770 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07002771static void hdd_ipa_uc_offload_enable_disable(struct hdd_adapter *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002772 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002773{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002774 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002775 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07002776 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002777 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002778
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002779 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002780 return;
2781
Yun Park8292dcb2016-10-07 16:46:06 -07002782 iface_context = adapter->ipa_context;
Jeff Johnson1b780e42017-10-31 14:11:45 -07002783 session_id = adapter->session_id;
Yun Park8292dcb2016-10-07 16:46:06 -07002784
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002785 if (!iface_context) {
2786 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2787 "Interface context is NULL");
2788 return;
2789 }
Zhu Jianminded9d2d2017-06-22 09:39:36 +08002790 if (session_id >= CSR_ROAM_SESSION_MAX) {
2791 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2792 "invalid session id: %d", session_id);
2793 return;
2794 }
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002795 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park199c2ed2017-10-02 11:24:22 -07002796 /*
2797 * This shouldn't happen :
2798 * IPA offload status is already set as desired
2799 */
2800 WARN_ON(1);
2801 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
Yun Parkb4f591d2017-03-29 15:51:01 -07002802 "%s (offload_type=%d, vdev_id=%d, enable=%d)",
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002803 "IPA offload status is already set",
2804 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002805 return;
2806 }
2807
Jeff Johnson1b780e42017-10-31 14:11:45 -07002808 if (wlan_hdd_validate_session_id(adapter->session_id)) {
Yun Park4540e862016-11-10 16:30:06 -08002809 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2810 "invalid session id: %d, offload_type=%d, enable=%d",
Jeff Johnson1b780e42017-10-31 14:11:45 -07002811 adapter->session_id, offload_type, enable);
Yun Park4540e862016-11-10 16:30:06 -08002812 return;
2813 }
2814
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302815 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002816 sizeof(ipa_offload_enable_disable));
2817 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002818 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002819 ipa_offload_enable_disable.enable = enable;
2820
Yun Park199c2ed2017-10-02 11:24:22 -07002821 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07002822 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002823 ipa_offload_enable_disable.offload_type,
2824 ipa_offload_enable_disable.vdev_id,
2825 ipa_offload_enable_disable.enable);
2826
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302827 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002828 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07002829 adapter->session_id, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302830 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07002831 "Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
2832 ipa_offload_enable_disable.offload_type,
2833 ipa_offload_enable_disable.vdev_id,
2834 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07002835 } else {
2836 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002837 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07002838 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002839 }
2840}
2841
2842/**
2843 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2844 * @work: uC OP work
2845 *
2846 * Return: None
2847 */
2848static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
2849{
2850 struct op_msg_type *msg;
2851 struct uc_op_work_struct *uc_op_work = container_of(work,
2852 struct uc_op_work_struct, work);
2853 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2854
2855 cds_ssr_protect(__func__);
2856
2857 msg = uc_op_work->msg;
2858 uc_op_work->msg = NULL;
Srinivas Girigowda97852372017-03-06 16:52:59 -08002859 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07002860 "posted msg %d", msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002861
2862 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
2863
2864 cds_ssr_unprotect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002865}
2866
2867/**
2868 * hdd_ipa_uc_op_event_handler() - Adapter lookup
2869 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2870 * @op_msg: operation message received from firmware
2871 * @hdd_ctx: Global HDD context
2872 *
2873 * Return: None
2874 */
2875static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
2876{
2877 struct hdd_ipa_priv *hdd_ipa;
2878 struct op_msg_type *msg;
2879 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302880 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002881
2882 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302883 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002884 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002885
2886 msg = (struct op_msg_type *)op_msg;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07002887 hdd_ipa = ((struct hdd_context *)hdd_ctx)->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002888
2889 if (unlikely(!hdd_ipa))
2890 goto end;
2891
2892 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Yun Parkb4f591d2017-03-29 15:51:01 -07002893 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid OP Code (%d)",
2894 msg->op_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002895 goto end;
2896 }
2897
2898 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
2899 if (uc_op_work->msg)
2900 /* When the same uC OPCODE is already pended, just return */
2901 goto end;
2902
2903 uc_op_work->msg = msg;
2904 schedule_work(&uc_op_work->work);
2905 return;
2906
2907end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302908 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002909}
2910
2911/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002912 * hdd_ipa_init_uc_op_work - init ipa uc op work
2913 * @work: struct work_struct
2914 * @work_handler: work_handler
2915 *
2916 * Return: none
2917 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002918static void hdd_ipa_init_uc_op_work(struct work_struct *work,
Yun Park637d6482016-10-05 10:51:33 -07002919 work_func_t work_handler)
Rajeev Kumar217f2172016-01-06 18:11:55 -08002920{
2921 INIT_WORK(work, work_handler);
2922}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002923
Yun Park637d6482016-10-05 10:51:33 -07002924#ifdef FEATURE_METERING
2925/**
2926 * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
2927 * IPA calls to get WLAN stats or set quota limit.
2928 * @priv: pointer to private data registered with IPA (we register a
2929 *» pointer to the global IPA context)
2930 * @evt: the IPA event which triggered the callback
2931 * @data: data associated with the event
2932 *
2933 * Return: None
2934 */
Yun Park6c86a662017-10-05 16:09:15 -07002935static void __hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Park637d6482016-10-05 10:51:33 -07002936 void *data)
2937{
2938 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07002939 struct hdd_adapter *adapter = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07002940 qdf_ipa_get_wdi_sap_stats_t *wdi_sap_stats;
2941 qdf_ipa_set_wifi_quota_t *ipa_set_quota;
Yun Park637d6482016-10-05 10:51:33 -07002942 int ret = 0;
2943
2944 if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2945 return;
2946
2947 adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
2948
2949 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
2950
2951 switch (evt) {
2952 case IPA_GET_WDI_SAP_STATS:
2953 /* fill-up ipa_get_wdi_sap_stats structure after getting
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07002954 * ipa_uc_fw_stats from FW
2955 */
Yun Park637d6482016-10-05 10:51:33 -07002956 wdi_sap_stats = data;
2957
2958 if (!adapter) {
2959 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2960 "IPA uC share stats failed - no adapter");
Yun Park6c86a662017-10-05 16:09:15 -07002961 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) =
2962 0;
Yun Park637d6482016-10-05 10:51:33 -07002963 return;
2964 }
2965
2966 INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
Yun Park637d6482016-10-05 10:51:33 -07002967 hdd_ipa_uc_sharing_stats_request(adapter,
Yun Park6c86a662017-10-05 16:09:15 -07002968 QDF_IPA_GET_WDI_SAP_STATS_RESET_STATS(wdi_sap_stats));
Yun Park637d6482016-10-05 10:51:33 -07002969 ret = wait_for_completion_timeout(
2970 &hdd_ipa->ipa_uc_sharing_stats_comp,
2971 msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
2972 if (!ret) {
2973 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2974 "IPA uC share stats request timed out");
Yun Park6c86a662017-10-05 16:09:15 -07002975 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
2976 = 0;
Yun Park637d6482016-10-05 10:51:33 -07002977 } else {
Yun Park6c86a662017-10-05 16:09:15 -07002978 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
2979 = 1;
Yun Park637d6482016-10-05 10:51:33 -07002980
Yun Park6c86a662017-10-05 16:09:15 -07002981 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(wdi_sap_stats)
2982 = hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
2983 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(wdi_sap_stats)
2984 = hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
2985 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(wdi_sap_stats)
2986 = hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
2987 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(wdi_sap_stats)
2988 = hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
2989 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(wdi_sap_stats)
2990 = hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
2991 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(wdi_sap_stats)
2992 = hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
2993 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(wdi_sap_stats)
2994 = hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
2995 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(wdi_sap_stats)
2996 = hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
Yun Park637d6482016-10-05 10:51:33 -07002997 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
2998 "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
2999 "IPA_GET_WDI_SAP_STATS",
Yun Park6c86a662017-10-05 16:09:15 -07003000 QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(
3001 wdi_sap_stats),
3002 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(
3003 wdi_sap_stats),
3004 QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(
3005 wdi_sap_stats),
3006 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(
3007 wdi_sap_stats),
3008 QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(
3009 wdi_sap_stats),
3010 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(
3011 wdi_sap_stats),
3012 QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(
3013 wdi_sap_stats),
3014 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(
3015 wdi_sap_stats),
3016 QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(
3017 wdi_sap_stats));
Yun Park637d6482016-10-05 10:51:33 -07003018 }
3019 break;
3020 case IPA_SET_WIFI_QUOTA:
3021 /* get ipa_set_wifi_quota structure from IPA and pass to FW
Jeff Johnsondcf84ce2017-10-05 09:26:24 -07003022 * through quota_exceeded field in ipa_uc_fw_stats
3023 */
Yun Park637d6482016-10-05 10:51:33 -07003024 ipa_set_quota = data;
3025
3026 if (!adapter) {
3027 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3028 "IPA uC set quota failed - no adapter");
3029 ipa_set_quota->set_valid = 0;
3030 return;
3031 }
3032
Yun Park777d7242017-03-30 15:38:33 -07003033 INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
Yun Park637d6482016-10-05 10:51:33 -07003034 hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
3035 ipa_set_quota->quota_bytes);
3036
3037 ret = wait_for_completion_timeout(
3038 &hdd_ipa->ipa_uc_set_quota_comp,
3039 msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
3040 if (!ret) {
3041 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3042 "IPA uC set quota request timed out");
Yun Park6c86a662017-10-05 16:09:15 -07003043 QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = 0;
Yun Park637d6482016-10-05 10:51:33 -07003044 } else {
Yun Park6c86a662017-10-05 16:09:15 -07003045 QDF_IPA_SET_WIFI_QUOTA_BYTES(ipa_set_quota) =
Yun Park637d6482016-10-05 10:51:33 -07003046 ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
3047 <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
Yun Park6c86a662017-10-05 16:09:15 -07003048 QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) =
Yun Park637d6482016-10-05 10:51:33 -07003049 hdd_ipa->ipa_quota_rsp.success;
3050 }
3051
3052 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
3053 ipa_set_quota->quota_bytes,
3054 ipa_set_quota->set_valid);
3055 break;
3056 }
3057}
3058
3059/**
3060 * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
3061 * IPA calls to get WLAN stats or set quota limit.
3062 * @priv: pointer to private data registered with IPA (we register a
Yun Parkb4f591d2017-03-29 15:51:01 -07003063 * pointer to the global IPA context)
Yun Park637d6482016-10-05 10:51:33 -07003064 * @evt: the IPA event which triggered the callback
3065 * @data: data associated with the event
3066 *
3067 * Return: None
3068 */
Yun Park6c86a662017-10-05 16:09:15 -07003069static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
Yun Park637d6482016-10-05 10:51:33 -07003070 void *data)
3071{
3072 cds_ssr_protect(__func__);
3073 __hdd_ipa_wdi_meter_notifier_cb(evt, data);
3074 cds_ssr_unprotect(__func__);
3075}
3076
Yun Parkb4f591d2017-03-29 15:51:01 -07003077static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07003078{
Yun Park637d6482016-10-05 10:51:33 -07003079 init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
3080 init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
3081}
3082#else
Yun Parkb4f591d2017-03-29 15:51:01 -07003083static void hdd_ipa_wdi_meter_notifier_cb(void)
3084{
3085}
3086
3087static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
Yun Park637d6482016-10-05 10:51:33 -07003088{
3089}
3090#endif
3091
Rajeev Kumar217f2172016-01-06 18:11:55 -08003092/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003093 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
3094 * @hdd_ctx: Global HDD context
3095 *
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003096 * This function is called to update IPA pipe configuration with resources
3097 * allocated by wlan driver (cds_pre_enable) before enabling it in FW
3098 * (cds_enable)
3099 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303100 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003101 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003102QDF_STATUS hdd_ipa_uc_ol_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003103{
Yun Parkb4f591d2017-03-29 15:51:01 -07003104 struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Leo Changfdb45c32016-10-28 11:09:23 -07003105 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Yun Parkbaa62862017-01-18 13:43:34 -08003106 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Parkb4f591d2017-03-29 15:51:01 -07003107 uint8_t i;
3108 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003109
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003110 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3111 return QDF_STATUS_SUCCESS;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003112
Yun Park199c2ed2017-10-02 11:24:22 -07003113 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003114
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003115 /* Do only IPA Pipe specific configuration here. All one time
3116 * initialization wrt IPA UC shall in hdd_ipa_init and those need
3117 * to be reinit at SSR shall in be SSR deinit / reinit functions.
3118 */
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003119 if (!pdev || !soc) {
3120 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL");
Yun Parkb4f591d2017-03-29 15:51:01 -07003121 status = QDF_STATUS_E_FAILURE;
Yun Parkbaa62862017-01-18 13:43:34 -08003122 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003123 }
Yun Parkb4f591d2017-03-29 15:51:01 -07003124 if (cdp_ipa_get_resource(soc, (struct cdp_pdev *)pdev)) {
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003125 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
3126 "IPA UC resource alloc fail");
Yun Park199c2ed2017-10-02 11:24:22 -07003127 status = QDF_STATUS_E_FAILURE;
3128 goto fail_return;
Manikandan Mohanbb8a7ee2017-02-09 11:26:53 -08003129 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003130
Yun Parkb4f591d2017-03-29 15:51:01 -07003131 if (true == hdd_ipa->uc_loaded) {
3132 status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
3133 hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
3134 hdd_ipa_wdi_meter_notifier_cb,
3135 hdd_ctx->config->IpaDescSize,
3136 hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
3137 &hdd_ipa->tx_pipe_handle,
3138 &hdd_ipa->rx_pipe_handle);
3139 if (status) {
Yun Parkbaa62862017-01-18 13:43:34 -08003140 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkb4f591d2017-03-29 15:51:01 -07003141 "Failure to setup IPA pipes (status=%d)",
3142 status);
Yun Park199c2ed2017-10-02 11:24:22 -07003143 status = QDF_STATUS_E_FAILURE;
3144 goto fail_return;
Yun Parkbaa62862017-01-18 13:43:34 -08003145 }
Yun Park637d6482016-10-05 10:51:33 -07003146
Yun Parkb4f591d2017-03-29 15:51:01 -07003147 cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev);
3148 hdd_ipa_init_metering(hdd_ipa);
Manikandan Mohan153a4c32017-02-16 15:04:30 -08003149 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003150
Yun Parkb4f591d2017-03-29 15:51:01 -07003151 cdp_ipa_register_op_cb(soc, (struct cdp_pdev *)pdev,
Yun Parkbaa62862017-01-18 13:43:34 -08003152 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
3153
Yun Parkb4f591d2017-03-29 15:51:01 -07003154 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
3155 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
3156 hdd_ipa_uc_fw_op_event_handler);
3157 hdd_ipa->uc_op_work[i].msg = NULL;
3158 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003159
Yun Parkbaa62862017-01-18 13:43:34 -08003160fail_return:
Yun Park199c2ed2017-10-02 11:24:22 -07003161 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: status=%d", status);
Yun Parkb4f591d2017-03-29 15:51:01 -07003162 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003163}
3164
Leo Change3e49442015-10-26 20:07:13 -07003165/**
Yun Parkd8fb1a82017-10-13 16:48:20 -07003166 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
3167 * @hdd_ipa: pointer to HDD IPA struct
3168 *
3169 * Return: none
3170 */
3171static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
3172{
3173 struct ipa_uc_pending_event *pending_event = NULL;
3174
3175 while (qdf_list_remove_front(&hdd_ipa->pending_event,
3176 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
3177 qdf_mem_free(pending_event);
3178}
3179
3180/**
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303181 * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes
3182 * @hdd_ctx: Global HDD context
3183 *
3184 * Return: 0 on success, negativer errno on error
3185 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003186int hdd_ipa_uc_ol_deinit(struct hdd_context *hdd_ctx)
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303187{
3188 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
3189 int ret = 0;
Yun Parkb4f591d2017-03-29 15:51:01 -07003190 QDF_STATUS status;
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303191
Yun Park199c2ed2017-10-02 11:24:22 -07003192 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003193
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303194 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
3195 return ret;
3196
Sravan Kumar Kairam374a8682017-05-15 13:19:44 +05303197 if (!hdd_ipa->ipa_pipes_down)
3198 hdd_ipa_uc_disable_pipes(hdd_ipa);
3199
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303200 if (true == hdd_ipa->uc_loaded) {
Yun Parkb4f591d2017-03-29 15:51:01 -07003201 status = cdp_ipa_cleanup(cds_get_context(QDF_MODULE_ID_SOC),
3202 hdd_ipa->tx_pipe_handle,
3203 hdd_ipa->rx_pipe_handle);
3204 if (status) {
3205 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3206 "Failure to cleanup IPA pipes (status=%d)",
3207 status);
3208 return -EFAULT;
3209 }
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303210 }
3211
Yun Parkd8fb1a82017-10-13 16:48:20 -07003212 hdd_ipa_cleanup_pending_event(hdd_ipa);
3213
Yun Park199c2ed2017-10-02 11:24:22 -07003214 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: ret=%d", ret);
Sravan Kumar Kairam71121712017-04-15 00:34:42 +05303215 return ret;
3216}
3217
3218/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003219 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07003220 * @hdd_ctx: hdd main context
3221 *
3222 * Force shutdown IPA pipe
3223 * Independent of FW pipe status, IPA pipe shutdonw progress
3224 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3225 * independent from FW pipe status
3226 *
3227 * Return: NONE
3228 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003229static void __hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07003230{
3231 struct hdd_ipa_priv *hdd_ipa;
3232
Yun Park199c2ed2017-10-02 11:24:22 -07003233 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003234
Leo Change3e49442015-10-26 20:07:13 -07003235 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
3236 return;
3237
3238 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
3239 if (false == hdd_ipa->ipa_pipes_down) {
Yun Park46255682017-10-09 15:56:34 -07003240 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Parkb4f591d2017-03-29 15:51:01 -07003241 "IPA pipes are not down yet, force shutdown");
Leo Change3e49442015-10-26 20:07:13 -07003242 hdd_ipa_uc_disable_pipes(hdd_ipa);
3243 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08003244 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb4f591d2017-03-29 15:51:01 -07003245 "IPA pipes are down, do nothing");
Leo Change3e49442015-10-26 20:07:13 -07003246 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003247
Yun Park199c2ed2017-10-02 11:24:22 -07003248 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
Leo Change3e49442015-10-26 20:07:13 -07003249}
3250
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003251/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003252 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
3253 * __hdd_ipa_uc_force_pipe_shutdown
3254 * @hdd_ctx: hdd main context
3255 *
3256 * Force shutdown IPA pipe
3257 * Independent of FW pipe status, IPA pipe shutdonw progress
3258 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
3259 * independent from FW pipe status
3260 *
3261 * Return: NONE
3262 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003263void hdd_ipa_uc_force_pipe_shutdown(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003264{
3265 cds_ssr_protect(__func__);
3266 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
3267 cds_ssr_unprotect(__func__);
3268}
3269
3270/**
Govind Singh9c58eba2016-09-02 16:23:06 +05303271 * hdd_ipa_msg_free_fn() - Free an IPA message
3272 * @buff: pointer to the IPA message
3273 * @len: length of the IPA message
3274 * @type: type of IPA message
3275 *
3276 * Return: None
3277 */
3278static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
3279{
Srinivas Girigowda97852372017-03-06 16:52:59 -08003280 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "msg type:%d, len:%d", type, len);
Govind Singh9c58eba2016-09-02 16:23:06 +05303281 ghdd_ipa->stats.num_free_msg++;
3282 qdf_mem_free(buff);
3283}
3284
Govind Singh9c58eba2016-09-02 16:23:06 +05303285/**
jge62037862016-12-09 10:44:33 +08003286 * hdd_ipa_uc_send_evt() - send event to ipa
3287 * @hdd_ctx: pointer to hdd context
3288 * @type: event type
3289 * @mac_addr: pointer to mac address
3290 *
3291 * Send event to IPA driver
Govind Singh9c58eba2016-09-02 16:23:06 +05303292 *
3293 * Return: 0 - Success
3294 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003295static int hdd_ipa_uc_send_evt(struct hdd_adapter *adapter,
Yun Park6c86a662017-10-05 16:09:15 -07003296 qdf_ipa_wlan_event_t type, uint8_t *mac_addr)
Govind Singh9c58eba2016-09-02 16:23:06 +05303297{
jge62037862016-12-09 10:44:33 +08003298 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07003299 qdf_ipa_msg_meta_t meta;
3300 qdf_ipa_wlan_msg_t *msg;
Govind Singh9c58eba2016-09-02 16:23:06 +05303301 int ret = 0;
jge62037862016-12-09 10:44:33 +08003302
Yun Park6c86a662017-10-05 16:09:15 -07003303 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
3304 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
jge62037862016-12-09 10:44:33 +08003305 if (msg == NULL) {
3306 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3307 "msg allocation failed");
3308 return -ENOMEM;
3309 }
3310
Yun Park6c86a662017-10-05 16:09:15 -07003311 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
3312 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), adapter->dev->name,
jge62037862016-12-09 10:44:33 +08003313 IPA_RESOURCE_NAME_MAX);
Yun Park6c86a662017-10-05 16:09:15 -07003314 memcpy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, ETH_ALEN);
Yun Park199c2ed2017-10-02 11:24:22 -07003315 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Yun Park6c86a662017-10-05 16:09:15 -07003316 QDF_IPA_WLAN_MSG_NAME(msg), QDF_IPA_MSG_META_MSG_TYPE(&meta));
3317 ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
jge62037862016-12-09 10:44:33 +08003318 if (ret) {
3319 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3320 "%s: Evt: %d fail:%d",
Yun Park6c86a662017-10-05 16:09:15 -07003321 QDF_IPA_WLAN_MSG_NAME(msg),
3322 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
jge62037862016-12-09 10:44:33 +08003323 qdf_mem_free(msg);
3324 return ret;
3325 }
3326
3327 hdd_ipa->stats.num_send_msg++;
3328
3329 return ret;
3330}
3331
3332/**
3333 * hdd_ipa_uc_disconnect_client() - send client disconnect event
3334 * @hdd_ctx: pointer to hdd adapter
3335 *
3336 * Send disconnect client event to IPA driver during SSR
3337 *
3338 * Return: 0 - Success
3339 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003340static int hdd_ipa_uc_disconnect_client(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003341{
3342 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3343 int ret = 0;
Govind Singh9c58eba2016-09-02 16:23:06 +05303344 int i;
3345
Yun Park199c2ed2017-10-02 11:24:22 -07003346 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Govind Singh9c58eba2016-09-02 16:23:06 +05303347 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003348 if (qdf_is_macaddr_broadcast(&adapter->sta_info[i].sta_mac))
Govind Singh9c58eba2016-09-02 16:23:06 +05303349 continue;
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003350 if ((adapter->sta_info[i].in_use) &&
3351 (!adapter->sta_info[i].is_deauth_in_progress) &&
jge62037862016-12-09 10:44:33 +08003352 hdd_ipa->sap_num_connected_sta) {
3353 hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT,
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003354 adapter->sta_info[i].sta_mac.bytes);
jge62037862016-12-09 10:44:33 +08003355 hdd_ipa->sap_num_connected_sta--;
Govind Singh9c58eba2016-09-02 16:23:06 +05303356 }
3357 }
Yun Park199c2ed2017-10-02 11:24:22 -07003358 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07003359 hdd_ipa->sap_num_connected_sta);
Govind Singh9c58eba2016-09-02 16:23:06 +05303360
3361 return ret;
3362}
3363
3364/**
jge62037862016-12-09 10:44:33 +08003365 * hdd_ipa_uc_disconnect_ap() - send ap disconnect event
3366 * @hdd_ctx: pointer to hdd adapter
3367 *
3368 * Send disconnect ap event to IPA driver during SSR
Govind Singh9c58eba2016-09-02 16:23:06 +05303369 *
3370 * Return: 0 - Success
3371 */
jge62037862016-12-09 10:44:33 +08003372
Jeff Johnson49d45e62017-08-29 14:30:42 -07003373static int hdd_ipa_uc_disconnect_ap(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003374{
3375 int ret = 0;
3376
Yun Park199c2ed2017-10-02 11:24:22 -07003377 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003378 if (adapter->ipa_context) {
jge62037862016-12-09 10:44:33 +08003379 hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT,
3380 adapter->dev->dev_addr);
Yun Parkfec73dc2017-09-06 10:40:07 -07003381 }
Yun Park199c2ed2017-10-02 11:24:22 -07003382 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
jge62037862016-12-09 10:44:33 +08003383
3384 return ret;
3385}
3386
jge62037862016-12-09 10:44:33 +08003387/**
3388 * hdd_ipa_uc_disconnect_sta() - send sta disconnect event
3389 * @hdd_ctx: pointer to hdd adapter
3390 *
3391 * Send disconnect sta event to IPA driver during SSR
3392 *
3393 * Return: 0 - Success
3394 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07003395static int hdd_ipa_uc_disconnect_sta(struct hdd_adapter *adapter)
jge62037862016-12-09 10:44:33 +08003396{
Jeff Johnsond377dce2017-10-04 10:32:42 -07003397 struct hdd_station_ctx *sta_ctx;
jge62037862016-12-09 10:44:33 +08003398 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3399 int ret = 0;
3400
Yun Park199c2ed2017-10-02 11:24:22 -07003401 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08003402 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jge62037862016-12-09 10:44:33 +08003403 hdd_ipa->sta_connected) {
Jeff Johnsond377dce2017-10-04 10:32:42 -07003404 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
jge62037862016-12-09 10:44:33 +08003405 hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT,
Jeff Johnsond377dce2017-10-04 10:32:42 -07003406 sta_ctx->conn_info.bssId.bytes);
jge62037862016-12-09 10:44:33 +08003407 }
Yun Park199c2ed2017-10-02 11:24:22 -07003408 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
jge62037862016-12-09 10:44:33 +08003409
3410 return ret;
3411}
jge62037862016-12-09 10:44:33 +08003412
3413/**
3414 * hdd_ipa_uc_disconnect() - send disconnect ipa event
3415 * @hdd_ctx: pointer to hdd context
3416 *
3417 * Send disconnect event to IPA driver during SSR
3418 *
3419 * Return: 0 - Success
3420 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003421static int hdd_ipa_uc_disconnect(struct hdd_context *hdd_ctx)
Govind Singh9c58eba2016-09-02 16:23:06 +05303422{
Jeff Johnson49d45e62017-08-29 14:30:42 -07003423 struct hdd_adapter *adapter;
Govind Singh9c58eba2016-09-02 16:23:06 +05303424 int ret = 0;
3425
Dustin Brown920397d2017-12-13 16:27:50 -08003426 hdd_for_each_adapter(hdd_ctx, adapter) {
jge62037862016-12-09 10:44:33 +08003427 if (adapter->device_mode == QDF_SAP_MODE) {
3428 hdd_ipa_uc_disconnect_client(adapter);
3429 hdd_ipa_uc_disconnect_ap(adapter);
3430 } else if (adapter->device_mode == QDF_STA_MODE) {
3431 hdd_ipa_uc_disconnect_sta(adapter);
3432 }
Govind Singh9c58eba2016-09-02 16:23:06 +05303433 }
3434
3435 return ret;
3436}
3437
3438/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003439 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003440 *
3441 * Deinit basic IPA UC host side to be in sync reloaded FW during
3442 * SSR
3443 *
3444 * Return: 0 - Success
3445 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003446static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003447{
3448 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3449 int idx;
3450 struct hdd_ipa_iface_context *iface_context;
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003451 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452
Yun Park199c2ed2017-10-02 11:24:22 -07003453 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003454
Arun Khandavallicc544b32017-01-30 19:52:16 +05303455 if (!hdd_ipa)
3456 return 0;
3457
3458 hdd_ctx = hdd_ipa->hdd_ctx;
3459 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003460 return 0;
3461
jge62037862016-12-09 10:44:33 +08003462 /* send disconnect to ipa driver */
Arun Khandavallicc544b32017-01-30 19:52:16 +05303463 hdd_ipa_uc_disconnect(hdd_ctx);
jge62037862016-12-09 10:44:33 +08003464
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003465 /* Clean up HDD IPA interfaces */
3466 for (idx = 0; (hdd_ipa->num_iface > 0) &&
3467 (idx < HDD_IPA_MAX_IFACE); idx++) {
3468 iface_context = &hdd_ipa->iface_context[idx];
Manikandan Mohaneab58242017-02-17 14:21:53 -08003469 if (iface_context->adapter && iface_context->adapter->magic ==
3470 WLAN_HDD_ADAPTER_MAGIC)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003471 hdd_ipa_cleanup_iface(iface_context);
3472 }
Manikandan Mohaneab58242017-02-17 14:21:53 -08003473 hdd_ipa->num_iface = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003474 /* After SSR, wlan driver reloads FW again. But we need to protect
3475 * IPA submodule during SSR transient state. So deinit basic IPA
3476 * UC host side to be in sync with reloaded FW during SSR
3477 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003478
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303479 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003480 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
3481 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
3482 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
3483 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303484 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003485
Guolei Bianca144d82016-11-10 11:07:42 +08003486 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
3487 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
3488
Manikandan Mohan2e803a02017-02-14 14:57:53 -08003489 for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) {
3490 cancel_work_sync(&hdd_ipa->uc_op_work[idx].work);
3491 qdf_mem_free(hdd_ipa->uc_op_work[idx].msg);
3492 hdd_ipa->uc_op_work[idx].msg = NULL;
3493 }
Yun Parkfec73dc2017-09-06 10:40:07 -07003494
Yun Park199c2ed2017-10-02 11:24:22 -07003495 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003496 return 0;
3497}
3498
3499/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003500 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
3501 *
3502 * Deinit basic IPA UC host side to be in sync reloaded FW during
3503 * SSR
3504 *
3505 * Return: 0 - Success
3506 */
3507int hdd_ipa_uc_ssr_deinit(void)
3508{
3509 int ret;
3510
3511 cds_ssr_protect(__func__);
3512 ret = __hdd_ipa_uc_ssr_deinit();
3513 cds_ssr_unprotect(__func__);
3514
3515 return ret;
3516}
3517
3518/**
3519 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003520 *
3521 * Init basic IPA UC host side to be in sync with reloaded FW after
3522 * SSR to resume IPA UC operations
3523 *
3524 * Return: 0 - Success
3525 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003526static int __hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003527{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003528
Arun Khandavallicc544b32017-01-30 19:52:16 +05303529 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3530 int i;
3531 struct hdd_ipa_iface_context *iface_context = NULL;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303532
Yun Park199c2ed2017-10-02 11:24:22 -07003533 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07003534
Arun Khandavallicc544b32017-01-30 19:52:16 +05303535 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
3536 return 0;
3537
Arun Khandavallicc544b32017-01-30 19:52:16 +05303538 /* Create the interface context */
3539 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3540 iface_context = &hdd_ipa->iface_context[i];
3541 iface_context->hdd_ipa = hdd_ipa;
3542 iface_context->cons_client =
3543 hdd_ipa_adapter_2_client[i].cons_client;
3544 iface_context->prod_client =
3545 hdd_ipa_adapter_2_client[i].prod_client;
3546 iface_context->iface_id = i;
3547 iface_context->adapter = NULL;
3548 }
3549 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
3550 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
3551 hdd_ipa->vdev_offload_enabled[i] = false;
3552 }
3553
3554 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3555 hdd_ipa->resource_loading = false;
3556 hdd_ipa->resource_unloading = false;
3557 hdd_ipa->sta_connected = 0;
3558 hdd_ipa->ipa_pipes_down = true;
3559 hdd_ipa->uc_loaded = true;
Arun Khandavallicc544b32017-01-30 19:52:16 +05303560 }
3561
Yun Park199c2ed2017-10-02 11:24:22 -07003562 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003563 return 0;
3564}
Leo Chang3bc8fed2015-11-13 10:59:47 -08003565
3566/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003567 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
3568 *
3569 * Init basic IPA UC host side to be in sync with reloaded FW after
3570 * SSR to resume IPA UC operations
3571 *
3572 * Return: 0 - Success
3573 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003574int hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003575{
3576 int ret;
3577
3578 cds_ssr_protect(__func__);
Arun Khandavallicc544b32017-01-30 19:52:16 +05303579 ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003580 cds_ssr_unprotect(__func__);
3581
3582 return ret;
3583}
3584
3585/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003586 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
3587 * @work: scheduled work
3588 *
3589 * When IPA resources are released in hdd_ipa_rm_try_release() we do
3590 * not want to immediately release the wake lock since the system
3591 * would then potentially try to suspend when there is a healthy data
3592 * rate. Deferred work is scheduled and this function handles the
3593 * work. When this function is called, if the IPA resource is still
3594 * released then we release the wake lock.
3595 *
3596 * Return: None
3597 */
3598static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
3599{
3600 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
3601 struct hdd_ipa_priv,
3602 wake_lock_work);
3603
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303604 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003605
3606 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
3607 goto end;
3608
3609 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303610 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003611 WIFI_POWER_EVENT_WAKELOCK_IPA);
3612
3613end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303614 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003615}
3616
3617/**
3618 * hdd_ipa_rm_request() - Request resource from IPA
3619 * @hdd_ipa: Global HDD IPA context
3620 *
3621 * Return: 0 on success, negative errno on error
3622 */
3623static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
3624{
3625 int ret = 0;
3626
3627 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3628 return 0;
3629
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303630 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003631
3632 switch (hdd_ipa->rm_state) {
3633 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303634 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003635 return 0;
3636 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303637 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638 return -EINPROGRESS;
3639 case HDD_IPA_RM_RELEASED:
3640 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
3641 break;
3642 }
3643
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303644 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003645
Yun Park6c86a662017-10-05 16:09:15 -07003646 ret = qdf_ipa_rm_inactivity_timer_request_resource(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003647 IPA_RM_RESOURCE_WLAN_PROD);
3648
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303649 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003650 if (ret == 0) {
3651 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3652 hdd_ipa->stats.num_rm_grant_imm++;
3653 }
3654
3655 cancel_delayed_work(&hdd_ipa->wake_lock_work);
3656 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303657 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003658 WIFI_POWER_EVENT_WAKELOCK_IPA);
3659 hdd_ipa->wake_lock_released = false;
3660 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303661 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003662
3663 return ret;
3664}
3665
3666/**
3667 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
3668 * @hdd_ipa: Global HDD IPA context
3669 *
3670 * Return: 0 if resources released, negative errno otherwise
3671 */
3672static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
3673{
3674 int ret = 0;
3675
3676 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3677 return 0;
3678
3679 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3680 return -EAGAIN;
3681
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303682 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003683
Nirav Shahcbc6d722016-03-01 16:24:53 +05303684 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303685 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003686 return -EAGAIN;
3687 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303688 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003689
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303690 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003691 switch (hdd_ipa->rm_state) {
3692 case HDD_IPA_RM_GRANTED:
3693 break;
3694 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303695 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003696 return -EINPROGRESS;
3697 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303698 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003699 return 0;
3700 }
3701
3702 /* IPA driver returns immediately so set the state here to avoid any
3703 * race condition.
3704 */
3705 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
3706 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303707 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003708
Yun Park6c86a662017-10-05 16:09:15 -07003709 ret = qdf_ipa_rm_inactivity_timer_release_resource(
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07003710 IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003711
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303712 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003713 if (unlikely(ret != 0)) {
3714 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
3715 WARN_ON(1);
Yun Park199c2ed2017-10-02 11:24:22 -07003716 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
3717 "ipa_rm_inactivity_timer_release_resource returnied fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003718 }
3719
3720 /*
3721 * If wake_lock is released immediately, kernel would try to suspend
3722 * immediately as well, Just avoid ping-pong between suspend-resume
3723 * while there is healthy amount of data transfer going on by
3724 * releasing the wake_lock after some delay.
3725 */
3726 schedule_delayed_work(&hdd_ipa->wake_lock_work,
3727 msecs_to_jiffies
3728 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
3729
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303730 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003731
3732 return ret;
3733}
3734
3735/**
3736 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
3737 * @user_data: user data registered with IPA
3738 * @event: the IPA resource manager event that occurred
3739 * @data: the data associated with the event
3740 *
3741 * Return: None
3742 */
Yun Park6c86a662017-10-05 16:09:15 -07003743static void hdd_ipa_rm_notify(void *user_data, qdf_ipa_rm_event_t event,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003744 unsigned long data)
3745{
3746 struct hdd_ipa_priv *hdd_ipa = user_data;
3747
3748 if (unlikely(!hdd_ipa))
3749 return;
3750
3751 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3752 return;
3753
Srinivas Girigowda97852372017-03-06 16:52:59 -08003754 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003755
3756 switch (event) {
3757 case IPA_RM_RESOURCE_GRANTED:
3758 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3759 /* RM Notification comes with ISR context
3760 * it should be serialized into work queue to avoid
3761 * ISR sleep problem
3762 */
3763 hdd_ipa->uc_rm_work.event = event;
3764 schedule_work(&hdd_ipa->uc_rm_work.work);
3765 break;
3766 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303767 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003768 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303769 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003770 hdd_ipa->stats.num_rm_grant++;
3771 break;
3772
3773 case IPA_RM_RESOURCE_RELEASED:
Srinivas Girigowda97852372017-03-06 16:52:59 -08003774 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003775 hdd_ipa->resource_unloading = false;
3776 break;
3777
3778 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303779 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003780 break;
3781 }
3782}
3783
3784/**
3785 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
3786 *
3787 * Callback function registered with IPA that is called when IPA wants
3788 * to release the WLAN consumer resource
3789 *
3790 * Return: 0 if the request is granted, negative errno otherwise
3791 */
3792static int hdd_ipa_rm_cons_release(void)
3793{
3794 return 0;
3795}
3796
3797/**
3798 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
3799 *
3800 * Callback function registered with IPA that is called when IPA wants
3801 * to access the WLAN consumer resource
3802 *
3803 * Return: 0 if the request is granted, negative errno otherwise
3804 */
3805static int hdd_ipa_rm_cons_request(void)
3806{
Yun Park4d8b60a2015-10-22 13:59:32 -07003807 int ret = 0;
3808
3809 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303810 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003811 "IPA resource loading in progress");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003812 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07003813 ret = -EINPROGRESS;
3814 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303815 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Parkb4f591d2017-03-29 15:51:01 -07003816 "IPA resource unloading in progress");
Yun Park4d8b60a2015-10-22 13:59:32 -07003817 ghdd_ipa->pending_cons_req = true;
3818 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003819 }
Yun Park4d8b60a2015-10-22 13:59:32 -07003820
3821 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003822}
3823
3824/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003825 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826 * @hdd_ctx: Global HDD context
3827 * @tx_packets: Number of packets transmitted in the last sample period
3828 * @rx_packets: Number of packets received in the last sample period
3829 *
3830 * Return: 0 on success, negative errno on error
3831 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07003832static int __hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx,
3833 uint64_t tx_packets,
3834 uint64_t rx_packets)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003835{
3836 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003837 struct hdd_ipa_priv *hdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07003838 qdf_ipa_rm_perf_profile_t profile;
Yun Parkb4f591d2017-03-29 15:51:01 -07003839 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003840 int ret;
3841
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003842 if (wlan_hdd_validate_context(hdd_ctx))
3843 return 0;
3844
3845 hdd_ipa = hdd_ctx->hdd_ipa;
3846
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003847 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
3848 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
3849 return 0;
3850
3851 memset(&profile, 0, sizeof(profile));
3852
3853 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3854 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3855 else if (tx_packets >
3856 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3857 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3858 else
3859 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3860
3861 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
3862 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
3863 else if (rx_packets >
3864 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
3865 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
3866 else
3867 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
3868
Yun Parkec845302016-12-15 09:22:57 -08003869 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003870 "CONS perf curr: %d, next: %d",
3871 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkec845302016-12-15 09:22:57 -08003872 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003873 "PROD perf curr: %d, next: %d",
3874 hdd_ipa->curr_prod_bw, next_prod_bw);
3875
3876 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003877 hdd_debug("Requesting CONS perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003878 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003879 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS,
3880 next_cons_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003881 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003882 hdd_err("RM CONS set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003883
3884 return ret;
3885 }
3886 hdd_ipa->curr_cons_bw = next_cons_bw;
3887 hdd_ipa->stats.num_cons_perf_req++;
3888 }
3889
3890 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Yun Parkb187d542016-11-14 18:10:04 -08003891 hdd_debug("Requesting PROD perf curr: %d, next: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003892 hdd_ipa->curr_prod_bw, next_prod_bw);
Yun Parkb4f591d2017-03-29 15:51:01 -07003893 ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD,
3894 next_prod_bw);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003895 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08003896 hdd_err("RM PROD set perf profile failed: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897 return ret;
3898 }
3899 hdd_ipa->curr_prod_bw = next_prod_bw;
3900 hdd_ipa->stats.num_prod_perf_req++;
3901 }
3902
3903 return 0;
3904}
3905
3906/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003907 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
3908 * @hdd_ctx: Global HDD context
3909 * @tx_packets: Number of packets transmitted in the last sample period
3910 * @rx_packets: Number of packets received in the last sample period
3911 *
3912 * Return: 0 on success, negative errno on error
3913 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07003914int hdd_ipa_set_perf_level(struct hdd_context *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003915 uint64_t rx_packets)
3916{
3917 int ret;
3918
3919 cds_ssr_protect(__func__);
3920 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
3921 cds_ssr_unprotect(__func__);
3922
3923 return ret;
3924}
3925
3926/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08003927 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
3928 * @work: struct work_struct
3929 * @work_handler: work_handler
3930 *
3931 * Return: none
3932 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08003933static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
3934 work_func_t work_handler)
3935{
3936 INIT_WORK(work, work_handler);
3937}
Rajeev Kumar217f2172016-01-06 18:11:55 -08003938
3939/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003940 * hdd_ipa_setup_rm() - Setup IPA resource management
3941 * @hdd_ipa: Global HDD IPA context
3942 *
3943 * Return: 0 on success, negative errno on error
3944 */
3945static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
3946{
Yun Park6c86a662017-10-05 16:09:15 -07003947 qdf_ipa_rm_create_params_t create_params = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003948 int ret;
3949
3950 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3951 return 0;
3952
Rajeev Kumar217f2172016-01-06 18:11:55 -08003953 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
3954 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003955 memset(&create_params, 0, sizeof(create_params));
Yun Park6c86a662017-10-05 16:09:15 -07003956 QDF_IPA_RM_CREATE_PARAMS_NAME(&create_params) =
3957 IPA_RM_RESOURCE_WLAN_PROD;
3958 QDF_IPA_RM_CREATE_PARAMS_USER_DATA(&create_params) =
3959 hdd_ipa;
3960 QDF_IPA_RM_CREATE_PARAMS_NOTIFY_CB(&create_params) =
3961 hdd_ipa_rm_notify;
3962 QDF_IPA_RM_CREATE_PARAMS_FLOOR_VOLTAGE(&create_params) =
3963 IPA_VOLTAGE_SVS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003964
Yun Park6c86a662017-10-05 16:09:15 -07003965 ret = qdf_ipa_rm_create_resource(&create_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003966 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303967 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003968 "Create RM resource failed: %d", ret);
3969 goto setup_rm_fail;
3970 }
3971
3972 memset(&create_params, 0, sizeof(create_params));
Yun Park6c86a662017-10-05 16:09:15 -07003973 QDF_IPA_RM_CREATE_PARAMS_NAME(&create_params) =
3974 IPA_RM_RESOURCE_WLAN_CONS;
3975 QDF_IPA_RM_CREATE_PARAMS_REQUEST_RESOURCE(&create_params) =
3976 hdd_ipa_rm_cons_request;
3977 QDF_IPA_RM_CREATE_PARAMS_RELEASE_RESOURCE(&create_params) =
3978 hdd_ipa_rm_cons_release;
3979 QDF_IPA_RM_CREATE_PARAMS_FLOOR_VOLTAGE(&create_params) =
3980 IPA_VOLTAGE_SVS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003981
Yun Park6c86a662017-10-05 16:09:15 -07003982 ret = qdf_ipa_rm_create_resource(&create_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003983 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303984 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003985 "Create RM CONS resource failed: %d", ret);
3986 goto delete_prod;
3987 }
3988
3989 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
3990 IPA_RM_RESOURCE_APPS_CONS);
3991
Yun Park6c86a662017-10-05 16:09:15 -07003992 ret = qdf_ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
3993 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003994 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303995 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003996 ret);
3997 goto timer_init_failed;
3998 }
3999
4000 /* Set the lowest bandwidth to start with */
4001 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
4002
4003 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304004 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004005 "Set perf level failed: %d", ret);
4006 goto set_perf_failed;
4007 }
4008
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304009 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004010 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
4011 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304012 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004013 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
4014 hdd_ipa->wake_lock_released = true;
4015 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
4016
4017 return ret;
4018
4019set_perf_failed:
4020 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4021
4022timer_init_failed:
4023 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
4024
4025delete_prod:
4026 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
4027
4028setup_rm_fail:
4029 return ret;
4030}
4031
4032/**
4033 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
4034 * @hdd_ipa: Global HDD IPA context
4035 *
4036 * Destroys all resources associated with the IPA resource manager
4037 *
4038 * Return: None
4039 */
4040static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
4041{
4042 int ret;
4043
4044 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4045 return;
4046
4047 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304048 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004049
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004050 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304051 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004052
4053 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
4054
Yun Park6c86a662017-10-05 16:09:15 -07004055 ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004056 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304057 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004058 "RM PROD resource delete failed %d", ret);
4059
Yun Park6c86a662017-10-05 16:09:15 -07004060 ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004061 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304062 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004063 "RM CONS resource delete failed %d", ret);
4064}
4065
tfyu0380a972017-07-13 18:19:37 +08004066#ifdef QCA_CONFIG_SMP
4067static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4068{
4069 return netif_rx_ni(skb);
4070}
4071#else
4072static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
4073{
4074 struct iphdr *ip_h;
4075 static atomic_t softirq_mitigation_cntr =
4076 ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH);
4077 int result;
4078
4079 ip_h = (struct iphdr *)(skb->data);
4080 if ((skb->protocol == htons(ETH_P_IP)) &&
4081 (ip_h->protocol == IPPROTO_ICMP)) {
4082 result = netif_rx_ni(skb);
4083 } else {
4084 /* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets
4085 * to avoid excessive softirq's.
4086 */
4087 if (atomic_dec_and_test(&softirq_mitigation_cntr)) {
4088 result = netif_rx_ni(skb);
4089 atomic_set(&softirq_mitigation_cntr,
4090 IPA_WLAN_RX_SOFTIRQ_THRESH);
4091 } else {
4092 result = netif_rx(skb);
4093 }
4094 }
4095
4096 return result;
4097}
4098#endif
4099
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004100/**
4101 * hdd_ipa_send_skb_to_network() - Send skb to kernel
4102 * @skb: network buffer
4103 * @adapter: network adapter
4104 *
4105 * Called when a network buffer is received which should not be routed
4106 * to the IPA module.
4107 *
4108 * Return: None
4109 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304110static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004111 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004112{
tfyu0380a972017-07-13 18:19:37 +08004113 int result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004114 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4115 unsigned int cpu_index;
4116
4117 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Jeff Johnson36e74c42017-09-18 08:15:42 -07004118 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid adapter: 0x%pK",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004119 adapter);
Yun Park46255682017-10-09 15:56:34 -07004120 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004121 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004122 return;
4123 }
4124
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004125 if (cds_is_driver_unloading()) {
Yun Park46255682017-10-09 15:56:34 -07004126 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004127 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004128 return;
4129 }
4130
4131 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
4132 skb->dev = adapter->dev;
4133 skb->protocol = eth_type_trans(skb, skb->dev);
4134 skb->ip_summed = CHECKSUM_NONE;
4135
4136 cpu_index = wlan_hdd_get_cpu();
4137
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004138 ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index];
tfyu0380a972017-07-13 18:19:37 +08004139 result = hdd_ipa_aggregated_rx_ind(skb);
4140 if (result == NET_RX_SUCCESS)
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004141 ++adapter->hdd_stats.tx_rx_stats.rx_delivered[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004142 else
Jeff Johnson6ced42c2017-10-20 12:48:11 -07004143 ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004144
Yun Park46255682017-10-09 15:56:34 -07004145 hdd_ipa->ipa_rx_net_send_count++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146}
4147
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004148/**
Leo Chang69c39692016-10-12 20:11:12 -07004149 * hdd_ipa_forward() - handle packet forwarding to wlan tx
4150 * @hdd_ipa: pointer to hdd ipa context
4151 * @adapter: network adapter
4152 * @skb: data pointer
4153 *
4154 * if exception packet has set forward bit, copied new packet should be
4155 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
4156 * put into pm queue and tx procedure will be differed
4157 *
4158 * Return: None
4159 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07004160static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004161 struct hdd_adapter *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07004162{
Leo Chang69c39692016-10-12 20:11:12 -07004163 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
4164
Leo Chang69c39692016-10-12 20:11:12 -07004165 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Yun Park01deb2c2017-06-14 15:21:44 -07004166
4167 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
4168 qdf_nbuf_ipa_owned_set(skb);
4169
Yun Park46255682017-10-09 15:56:34 -07004170 /* WLAN subsystem is in suspend, put in queue */
Leo Chang69c39692016-10-12 20:11:12 -07004171 if (hdd_ipa->suspended) {
4172 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Yun Park46255682017-10-09 15:56:34 -07004173 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4174 "Tx in suspend, put in queue");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004175 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
4176 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07004177 pm_tx_cb->exception = true;
4178 pm_tx_cb->adapter = adapter;
4179 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004180 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07004181 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
4182 hdd_ipa->stats.num_tx_queued++;
4183 } else {
4184 /* Resume, put packet into WLAN TX */
4185 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004186 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07004187 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07004188 "packet Tx fail");
Yun Parkb187d542016-11-14 18:10:04 -08004189 hdd_ipa->stats.num_tx_fwd_err++;
Leo Chang69c39692016-10-12 20:11:12 -07004190 } else {
Yun Parkb187d542016-11-14 18:10:04 -08004191 hdd_ipa->stats.num_tx_fwd_ok++;
Leo Chang69c39692016-10-12 20:11:12 -07004192 }
4193 }
4194}
4195
4196/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004197 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
4198 * @hdd_ipa: pointer to HDD IPA struct
4199 * @adapter: hdd adapter pointer
4200 * @desc: Firmware descriptor
4201 * @skb: Data buffer
4202 *
4203 * Return:
4204 * HDD_IPA_FORWARD_PKT_NONE
4205 * HDD_IPA_FORWARD_PKT_DISCARD
4206 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
4207 *
4208 */
4209
4210static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
4211 struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07004212 struct hdd_adapter *adapter,
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004213 uint8_t desc,
4214 qdf_nbuf_t skb)
4215{
4216 int ret = HDD_IPA_FORWARD_PKT_NONE;
Yun Park0dad1002017-07-14 14:57:01 -07004217 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
4218 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004219
4220 if ((desc & FW_RX_DESC_FORWARD_M)) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304221 if (!ol_txrx_fwd_desc_thresh_check(
Yun Park0dad1002017-07-14 14:57:01 -07004222 (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc,
4223 (struct cdp_pdev *)pdev,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004224 adapter->session_id))) {
Poddar, Siddarth8e3ee2d2016-11-29 20:17:01 +05304225 /* Drop the packet*/
4226 hdd_ipa->stats.num_tx_fwd_err++;
4227 kfree_skb(skb);
4228 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4229 return ret;
4230 }
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004231 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
4232 "Forward packet to Tx (fw_desc=%d)", desc);
4233 hdd_ipa->ipa_tx_forward++;
4234
4235 if ((desc & FW_RX_DESC_DISCARD_M)) {
4236 hdd_ipa_forward(hdd_ipa, adapter, skb);
Yun Park46255682017-10-09 15:56:34 -07004237 hdd_ipa->ipa_rx_internal_drop_count++;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004238 hdd_ipa->ipa_rx_discard++;
4239 ret = HDD_IPA_FORWARD_PKT_DISCARD;
4240 } else {
4241 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004242
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004243 if (cloned_skb)
4244 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
4245 else
4246 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park46255682017-10-09 15:56:34 -07004247 "tx skb alloc failed");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004248 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
4249 }
4250 }
4251
4252 return ret;
4253}
4254
4255/**
Yun Park637d6482016-10-05 10:51:33 -07004256 * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257 * @priv: pointer to private data registered with IPA (we register a
4258 * pointer to the global IPA context)
4259 * @evt: the IPA event which triggered the callback
4260 * @data: data associated with the event
4261 *
4262 * Return: None
4263 */
Yun Park6c86a662017-10-05 16:09:15 -07004264static void __hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
4265 unsigned long data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004266{
4267 struct hdd_ipa_priv *hdd_ipa = NULL;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004268 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304269 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004270 uint8_t iface_id;
4271 uint8_t session_id;
4272 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004273 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07004274 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004275
4276 hdd_ipa = (struct hdd_ipa_priv *)priv;
4277
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08004278 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
4279 return;
4280
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004281 switch (evt) {
4282 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05304283 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07004284
4285 /*
4286 * When SSR is going on or driver is unloading,
4287 * just drop the packets.
4288 */
4289 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
4290 if (0 != status) {
4291 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4292 "Invalid context: drop packet");
Yun Park46255682017-10-09 15:56:34 -07004293 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004294 kfree_skb(skb);
4295 return;
4296 }
4297
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004298 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4299 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004300 iface_id = hdd_ipa->vdev_to_iface[session_id];
Srinivas Girigowda97852372017-03-06 16:52:59 -08004301 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004302 "IPA_RECEIVE: session_id=%u, iface_id=%u",
4303 session_id, iface_id);
4304 } else {
4305 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
4306 }
4307
4308 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304309 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004310 "IPA_RECEIVE: Invalid iface_id: %u",
4311 iface_id);
Srinivas Girigowda97852372017-03-06 16:52:59 -08004312 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Yun Parkb187d542016-11-14 18:10:04 -08004313 "w2i -- skb",
4314 skb->data, HDD_IPA_DBG_DUMP_RX_LEN);
Yun Park46255682017-10-09 15:56:34 -07004315 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Parkf8d6a122016-10-11 15:49:43 -07004316 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004317 return;
4318 }
4319
4320 iface_context = &hdd_ipa->iface_context[iface_id];
4321 adapter = iface_context->adapter;
Yun Park16a78262017-02-01 12:15:03 -08004322 if (!adapter) {
4323 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4324 "IPA_RECEIVE: Adapter is NULL");
Yun Park46255682017-10-09 15:56:34 -07004325 hdd_ipa->ipa_rx_internal_drop_count++;
Yun Park16a78262017-02-01 12:15:03 -08004326 kfree_skb(skb);
4327 return;
4328 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004329
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304330 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);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004333 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4334 hdd_ipa->stats.num_rx_excep++;
4335 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
4336 } else {
4337 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
4338 }
4339
4340 iface_context->stats.num_rx_ipa_excep++;
4341
4342 /* Disable to forward Intra-BSS Rx packets when
4343 * ap_isolate=1 in hostapd.conf
4344 */
Jeff Johnsonb9424862017-10-30 08:49:35 -07004345 if (!adapter->session.ap.disable_intrabss_fwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004346 /*
4347 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
4348 * all Rx packets to IPA uC, which need to be forwarded
4349 * to other interface.
4350 * And, IPA driver will send back to WLAN host driver
4351 * through exception pipe with fw_desc field set by FW.
4352 * Here we are checking fw_desc field for FORWARD bit
4353 * set, and forward to Tx. Then copy to kernel stack
4354 * only when DISCARD bit is not set.
4355 */
4356 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004357 if (HDD_IPA_FORWARD_PKT_DISCARD ==
4358 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
4359 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08004360 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004361 } else {
Srinivas Girigowda97852372017-03-06 16:52:59 -08004362 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363 "Intra-BSS FWD is disabled-skip forward to Tx");
4364 }
4365
4366 hdd_ipa_send_skb_to_network(skb, adapter);
4367 break;
4368
4369 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304370 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004371 "w2i cb wrong event: 0x%x", evt);
4372 return;
4373 }
4374}
4375
4376/**
Yun Parkf8d6a122016-10-11 15:49:43 -07004377 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
4378 * @priv: pointer to private data registered with IPA (we register a
4379 * pointer to the global IPA context)
4380 * @evt: the IPA event which triggered the callback
4381 * @data: data associated with the event
4382 *
4383 * Return: None
4384 */
Yun Park6c86a662017-10-05 16:09:15 -07004385static void hdd_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Yun Parkf8d6a122016-10-11 15:49:43 -07004386 unsigned long data)
4387{
4388 cds_ssr_protect(__func__);
4389 __hdd_ipa_w2i_cb(priv, evt, data);
4390 cds_ssr_unprotect(__func__);
4391}
4392
4393/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004394 * hdd_ipa_nbuf_cb() - IPA TX complete callback
4395 * @skb: packet buffer which was transmitted
4396 *
4397 * Return: None
4398 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304399void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004400{
4401 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07004402 qdf_ipa_rx_data_t *ipa_tx_desc;
Yun Park52b2b992016-09-22 15:49:51 -07004403 struct hdd_ipa_tx_desc *tx_desc;
4404 uint16_t id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004405
Yun Park52b2b992016-09-22 15:49:51 -07004406 if (!qdf_nbuf_ipa_owned_get(skb)) {
4407 dev_kfree_skb_any(skb);
4408 return;
4409 }
4410
4411 /* Get Tx desc pointer from SKB CB */
4412 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
4413 tx_desc = hdd_ipa->tx_desc_list + id;
4414 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
4415
4416 /* Return Tx Desc to IPA */
4417 ipa_free_skb(ipa_tx_desc);
4418
4419 /* Return to free tx desc list */
4420 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4421 tx_desc->ipa_tx_desc_ptr = NULL;
4422 list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
4423 hdd_ipa->stats.num_tx_desc_q_cnt--;
4424 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004425
4426 hdd_ipa->stats.num_tx_comp_cnt++;
4427
4428 atomic_dec(&hdd_ipa->tx_ref_cnt);
4429
4430 hdd_ipa_rm_try_release(hdd_ipa);
4431}
4432
4433/**
4434 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
4435 * @iface_context: interface-specific IPA context
4436 * @ipa_tx_desc: packet data descriptor
4437 *
4438 * Return: None
4439 */
4440static void hdd_ipa_send_pkt_to_tl(
4441 struct hdd_ipa_iface_context *iface_context,
Yun Park6c86a662017-10-05 16:09:15 -07004442 qdf_ipa_rx_data_t *ipa_tx_desc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004443{
4444 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Jeff Johnson49d45e62017-08-29 14:30:42 -07004445 struct hdd_adapter *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304446 qdf_nbuf_t skb;
Yun Park52b2b992016-09-22 15:49:51 -07004447 struct hdd_ipa_tx_desc *tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004448
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304449 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004450 adapter = iface_context->adapter;
4451 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304452 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004453 ipa_free_skb(ipa_tx_desc);
4454 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304455 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004456 hdd_ipa_rm_try_release(hdd_ipa);
4457 return;
4458 }
4459
4460 /*
4461 * During CAC period, data packets shouldn't be sent over the air so
4462 * drop all the packets here
4463 */
hqu70708ab2017-10-10 17:52:01 +08004464 if (QDF_SAP_MODE == adapter->device_mode ||
4465 QDF_P2P_GO_MODE == adapter->device_mode) {
4466 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
4467 ipa_free_skb(ipa_tx_desc);
4468 qdf_spin_unlock_bh(&iface_context->interface_lock);
4469 iface_context->stats.num_tx_cac_drop++;
4470 hdd_ipa_rm_try_release(hdd_ipa);
4471 return;
4472 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004473 }
4474
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004475 ++adapter->stats.tx_packets;
4476
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304477 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004478
Yun Park6c86a662017-10-05 16:09:15 -07004479 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004480
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304481 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Yun Park52b2b992016-09-22 15:49:51 -07004482
4483 /* Store IPA Tx buffer ownership into SKB CB */
Nirav Shahcbc6d722016-03-01 16:24:53 +05304484 qdf_nbuf_ipa_owned_set(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004485 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05304486 qdf_nbuf_mapped_paddr_set(skb,
Yun Park6c86a662017-10-05 16:09:15 -07004487 QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc)
Houston Hoffman43d47fa2016-02-24 16:34:30 -08004488 + HDD_IPA_WLAN_FRAG_HEADER
4489 + HDD_IPA_WLAN_IPA_HEADER);
Yun Park6c86a662017-10-05 16:09:15 -07004490 QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004491 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
4492 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05304493 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494
Yun Park52b2b992016-09-22 15:49:51 -07004495 qdf_spin_lock_bh(&hdd_ipa->q_lock);
4496 /* get free Tx desc and assign ipa_tx_desc pointer */
4497 if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
4498 tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
4499 struct hdd_ipa_tx_desc, link);
4500 list_del(&tx_desc->link);
4501 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
4502 hdd_ipa->stats.num_tx_desc_q_cnt++;
4503 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4504 /* Store Tx Desc index into SKB CB */
4505 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
4506 } else {
4507 hdd_ipa->stats.num_tx_desc_error++;
4508 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
Yun Park52b2b992016-09-22 15:49:51 -07004509 ipa_free_skb(ipa_tx_desc);
4510 hdd_ipa_rm_try_release(hdd_ipa);
4511 return;
4512 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004513
Yun Park6c86a662017-10-05 16:09:15 -07004514 adapter->stats.tx_bytes += QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004515
Leo Changfdb45c32016-10-28 11:09:23 -07004516 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
Yun Park6c86a662017-10-05 16:09:15 -07004517 (struct cdp_vdev *)iface_context->tl_context,
4518 QDF_IPA_RX_DATA_SKB(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004519 if (skb) {
jiad05c1e812017-08-01 16:48:52 +08004520 qdf_nbuf_free(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004521 iface_context->stats.num_tx_err++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004522 return;
4523 }
4524
4525 atomic_inc(&hdd_ipa->tx_ref_cnt);
4526
4527 iface_context->stats.num_tx++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004528}
4529
4530/**
Leo Chang11545d62016-10-17 14:53:50 -07004531 * hdd_ipa_is_present() - get IPA hw status
4532 * @hdd_ctx: pointer to hdd context
4533 *
4534 * ipa_uc_reg_rdyCB is not directly designed to check
4535 * ipa hw status. This is an undocumented function which
4536 * has confirmed with IPA team.
4537 *
4538 * Return: true - ipa hw present
4539 * false - ipa hw not present
4540 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004541bool hdd_ipa_is_present(struct hdd_context *hdd_ctx)
Leo Chang11545d62016-10-17 14:53:50 -07004542{
4543 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07004544 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07004545 return true;
4546 else
4547 return false;
4548}
4549
4550/**
Leo Chang69c39692016-10-12 20:11:12 -07004551 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004552 * @work: pointer to the scheduled work
4553 *
4554 * Called during PM resume to send packets to TL which were queued
4555 * while host was in the process of suspending.
4556 *
4557 * Return: None
4558 */
Leo Chang69c39692016-10-12 20:11:12 -07004559static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004560{
4561 struct hdd_ipa_priv *hdd_ipa = container_of(work,
4562 struct hdd_ipa_priv,
4563 pm_work);
4564 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304565 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004566 uint32_t dequeued = 0;
4567
Leo Chang69c39692016-10-12 20:11:12 -07004568 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
4569 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304570 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304571 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4572 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304573 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004574
4575 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004576 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07004577 if (pm_tx_cb->exception) {
Yun Park46255682017-10-09 15:56:34 -07004578 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4579 "Flush Exception");
Govind Singh1dab23b2017-08-12 13:31:00 +05304580 if (pm_tx_cb->adapter->dev)
4581 hdd_softap_hard_start_xmit(skb,
4582 pm_tx_cb->adapter->dev);
Govind Singh02075942017-08-15 11:13:28 +05304583 else
4584 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004585 } else {
4586 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004587 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07004588 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304589 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004590 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304591 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07004592 qdf_wake_lock_release(&hdd_ipa->wake_lock,
4593 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594
4595 hdd_ipa->stats.num_tx_dequeued += dequeued;
4596 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
4597 hdd_ipa->stats.num_max_pm_queue = dequeued;
4598}
4599
4600/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004601 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004602 * @priv: pointer to private data registered with IPA (we register a
4603 * pointer to the interface-specific IPA context)
4604 * @evt: the IPA event which triggered the callback
4605 * @data: data associated with the event
4606 *
4607 * Return: None
4608 */
Yun Park6c86a662017-10-05 16:09:15 -07004609static void __hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
4610 unsigned long data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004611{
4612 struct hdd_ipa_priv *hdd_ipa = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07004613 qdf_ipa_rx_data_t *ipa_tx_desc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004614 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304615 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004616 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304617 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004618
Mukul Sharma81661ae2015-10-30 20:26:02 +05304619 iface_context = (struct hdd_ipa_iface_context *)priv;
Yun Park6c86a662017-10-05 16:09:15 -07004620 ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004621 hdd_ipa = iface_context->hdd_ipa;
4622
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08004624 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
4625 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004626 iface_context->stats.num_tx_drop++;
4627 return;
4628 }
4629
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004630 /*
4631 * When SSR is going on or driver is unloading, just drop the packets.
4632 * During SSR, there is no use in queueing the packets as STA has to
4633 * connect back any way
4634 */
4635 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304636 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637 ipa_free_skb(ipa_tx_desc);
4638 iface_context->stats.num_tx_drop++;
4639 return;
4640 }
4641
Yun Park6c86a662017-10-05 16:09:15 -07004642 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004643
Yun Parkb187d542016-11-14 18:10:04 -08004644 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
4645 "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004646
4647 /*
4648 * If PROD resource is not requested here then there may be cases where
4649 * IPA hardware may be clocked down because of not having proper
4650 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
4651 * workaround to request PROD resource while data is going over CONS
4652 * pipe to prevent the IPA hardware clockdown.
4653 */
4654 hdd_ipa_rm_request(hdd_ipa);
4655
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304656 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004657 /*
4658 * If host is still suspended then queue the packets and these will be
4659 * drained later when resume completes. When packet is arrived here and
4660 * host is suspended, this means that there is already resume is in
4661 * progress.
4662 */
4663 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304664 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004665 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4666 pm_tx_cb->iface_context = iface_context;
4667 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304668 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669 hdd_ipa->stats.num_tx_queued++;
4670
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304671 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004672 return;
4673 }
4674
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304675 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004676
4677 /*
4678 * If we are here means, host is not suspended, wait for the work queue
4679 * to finish.
4680 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004681 flush_work(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004682
4683 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
4684}
4685
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004686/*
4687 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
4688 * @priv: pointer to private data registered with IPA (we register a
4689 * pointer to the interface-specific IPA context)
4690 * @evt: the IPA event which triggered the callback
4691 * @data: data associated with the event
4692 *
4693 * Return: None
4694 */
Yun Park6c86a662017-10-05 16:09:15 -07004695static void hdd_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004696 unsigned long data)
4697{
4698 cds_ssr_protect(__func__);
4699 __hdd_ipa_i2w_cb(priv, evt, data);
4700 cds_ssr_unprotect(__func__);
4701}
4702
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004703/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004704 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004705 * @hdd_ctx: Global HDD context
4706 *
4707 * Return: 0 on success, negativer errno on error
4708 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004709static int __hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004710{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004711 struct hdd_ipa_priv *hdd_ipa;
4712
4713 if (wlan_hdd_validate_context(hdd_ctx))
4714 return 0;
4715
4716 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004717
4718 if (!hdd_ipa_is_enabled(hdd_ctx))
4719 return 0;
4720
4721 /*
4722 * Check if IPA is ready for suspend, If we are here means, there is
4723 * high chance that suspend would go through but just to avoid any race
4724 * condition after suspend started, these checks are conducted before
4725 * allowing to suspend.
4726 */
4727 if (atomic_read(&hdd_ipa->tx_ref_cnt))
4728 return -EAGAIN;
4729
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304730 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004731
4732 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304733 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004734 return -EAGAIN;
4735 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304736 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004737
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304738 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004739 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304740 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004741
4742 return 0;
4743}
4744
4745/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004746 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
4747 * @hdd_ctx: Global HDD context
4748 *
4749 * Return: 0 on success, negativer errno on error
4750 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004751int hdd_ipa_suspend(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004752{
4753 int ret;
4754
4755 cds_ssr_protect(__func__);
4756 ret = __hdd_ipa_suspend(hdd_ctx);
4757 cds_ssr_unprotect(__func__);
4758
4759 return ret;
4760}
4761
4762/**
4763 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004764 * hdd_ctx: Global HDD context
4765 *
4766 * Return: 0 on success, negative errno on error
4767 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004768static int __hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004769{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004770 struct hdd_ipa_priv *hdd_ipa;
4771
4772 if (wlan_hdd_validate_context(hdd_ctx))
4773 return 0;
4774
4775 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004776
4777 if (!hdd_ipa_is_enabled(hdd_ctx))
4778 return 0;
4779
4780 schedule_work(&hdd_ipa->pm_work);
4781
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304782 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004783 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304784 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004785
4786 return 0;
4787}
4788
4789/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004790 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
4791 * hdd_ctx: Global HDD context
4792 *
4793 * Return: 0 on success, negative errno on error
4794 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07004795int hdd_ipa_resume(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004796{
4797 int ret;
4798
4799 cds_ssr_protect(__func__);
4800 ret = __hdd_ipa_resume(hdd_ctx);
4801 cds_ssr_unprotect(__func__);
4802
4803 return ret;
4804}
4805
4806/**
Yun Park52b2b992016-09-22 15:49:51 -07004807 * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
4808 * @hdd_ipa: Global HDD IPA context
4809 *
4810 * Return: 0 on success, negative errno on error
4811 */
4812static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
4813{
4814 int i;
4815 uint32_t max_desc_cnt;
4816 struct hdd_ipa_tx_desc *tmp_desc;
4817
Yun Parkd9c528e2017-08-30 16:34:57 -07004818 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
Yun Park52b2b992016-09-22 15:49:51 -07004819
4820 INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
4821
jiad14fe4fb2017-08-08 13:33:14 +08004822 tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc) *
Yun Parkd9c528e2017-08-30 16:34:57 -07004823 max_desc_cnt);
Yun Park52b2b992016-09-22 15:49:51 -07004824
4825 if (!tmp_desc) {
4826 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Parkd9c528e2017-08-30 16:34:57 -07004827 "Free Tx descriptor allocation failed");
Yun Park52b2b992016-09-22 15:49:51 -07004828 return -ENOMEM;
4829 }
4830
4831 hdd_ipa->tx_desc_list = tmp_desc;
4832
4833 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07004834 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07004835 tmp_desc->id = i;
4836 tmp_desc->ipa_tx_desc_ptr = NULL;
4837 list_add_tail(&tmp_desc->link,
4838 &hdd_ipa->free_tx_desc_head);
4839 tmp_desc++;
4840 }
4841
4842 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
4843 hdd_ipa->stats.num_tx_desc_error = 0;
4844
4845 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
4846
4847 return 0;
4848}
4849
Yun Park9281cb72017-11-30 11:14:30 -08004850#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Yun Park52b2b992016-09-22 15:49:51 -07004851/**
Yun Park9281cb72017-11-30 11:14:30 -08004852 * hdd_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004853 * @hdd_ipa: Global HDD IPA context
Yun Park9281cb72017-11-30 11:14:30 -08004854 * @desc_fifo_sz: Number of descriptors
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004855 *
4856 * Return: 0 on success, negative errno on error
4857 */
Yun Park9281cb72017-11-30 11:14:30 -08004858static int hdd_ipa_setup_tx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
4859 int32_t desc_fifo_sz)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004860{
4861 int i, ret = 0;
Yun Park6c86a662017-10-05 16:09:15 -07004862 qdf_ipa_sys_connect_params_t *ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004863
4864 /*setup TX pipes */
4865 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4866 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
4867
4868 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
4869 ipa->desc_fifo_sz = desc_fifo_sz;
4870 ipa->priv = &hdd_ipa->iface_context[i];
4871 ipa->notify = hdd_ipa_i2w_cb;
4872
4873 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4874 ipa->ipa_ep_cfg.hdr.hdr_len =
4875 HDD_IPA_UC_WLAN_TX_HDR_LEN;
4876 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4877 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
4878 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
4879 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
4880 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
4881 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
4882 } else {
4883 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
4884 }
4885 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4886
4887 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4888 ipa->keep_ipa_awake = 1;
4889
Yun Park6c86a662017-10-05 16:09:15 -07004890 ret = qdf_ipa_setup_sys_pipe(ipa,
4891 &hdd_ipa->sys_pipe[i].conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004892 if (ret) {
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07004893 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4894 "Failed for pipe %d ret: %d", i, ret);
Yun Park9281cb72017-11-30 11:14:30 -08004895 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004896 }
4897 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
4898 }
4899
Yun Park9281cb72017-11-30 11:14:30 -08004900 return ret;
4901}
4902#else
4903/**
4904 * hdd_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
4905 * @hdd_ipa: Global HDD IPA context
4906 * @desc_fifo_sz: Number of descriptors
4907 *
4908 * Return: 0 on success, negative errno on error
4909 */
4910static int hdd_ipa_setup_tx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
4911 int32_t desc_fifo_sz)
4912{
4913 /*
4914 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
4915 * is enabled, where per vdev descriptors are supported in firmware.
4916 */
4917 return 0;
4918}
4919#endif
4920
4921/**
4922 * hdd_ipa_setup_rx_sys_pipe() - Setup IPA Rx 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_rx_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
4929 int32_t desc_fifo_sz)
4930{
4931 int ret = 0;
4932 qdf_ipa_sys_connect_params_t *ipa;
4933
4934 /*
4935 * Hard code it here, this can be extended if in case
4936 * PROD pipe is also per interface.
4937 * Right now there is no advantage of doing this.
4938 */
4939 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
4940
4941 ipa->client = IPA_CLIENT_WLAN1_PROD;
4942
4943 ipa->desc_fifo_sz = desc_fifo_sz;
4944 ipa->priv = hdd_ipa;
4945 ipa->notify = hdd_ipa_w2i_cb;
4946
4947 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
4948 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
4949 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
4950 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
4951
4952 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
4953 ipa->keep_ipa_awake = 1;
4954
4955 ret = qdf_ipa_setup_sys_pipe(ipa,
4956 &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl);
4957 if (ret) {
4958 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4959 "Failed for RX pipe: %d", ret);
4960 return ret;
4961 }
4962 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
4963
4964 return ret;
4965}
4966
4967/**
4968 * hdd_ipa_setup_sys_pipe() - Setup all IPA system pipes
4969 * @hdd_ipa: Global HDD IPA context
4970 *
4971 * Return: 0 on success, negative errno on error
4972 */
4973static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
4974{
4975 int i = HDD_IPA_MAX_IFACE, ret = 0;
4976 uint32_t desc_fifo_sz;
4977
4978 /* The maximum number of descriptors that can be provided to a BAM at
4979 * once is one less than the total number of descriptors that the buffer
4980 * can contain.
4981 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
4982 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
4983 * be provided at once.
4984 * Because of above requirement, one extra descriptor will be added to
4985 * make sure hardware always has one descriptor.
4986 */
4987 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
4988 + sizeof(struct sps_iovec);
4989
4990 ret = hdd_ipa_setup_tx_sys_pipe(hdd_ipa, desc_fifo_sz);
4991 if (ret) {
4992 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4993 "Failed for TX pipe: %d", ret);
4994 goto setup_sys_pipe_fail;
4995 }
4996
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004997 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park9281cb72017-11-30 11:14:30 -08004998 ret = hdd_ipa_setup_rx_sys_pipe(hdd_ipa, desc_fifo_sz);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305000 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park9281cb72017-11-30 11:14:30 -08005001 "Failed for RX pipe: %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005002 goto setup_sys_pipe_fail;
5003 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005004 }
5005
Yun Parkd9c528e2017-08-30 16:34:57 -07005006 /* Allocate free Tx desc list */
Yun Park52b2b992016-09-22 15:49:51 -07005007 ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
5008 if (ret)
5009 goto setup_sys_pipe_fail;
5010
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005011 return ret;
5012
5013setup_sys_pipe_fail:
5014
Yun Park9281cb72017-11-30 11:14:30 -08005015 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
5016 if (hdd_ipa->sys_pipe[i].conn_hdl_valid)
5017 qdf_ipa_teardown_sys_pipe(
5018 hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305019 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005020 sizeof(struct hdd_ipa_sys_pipe));
5021 }
5022
5023 return ret;
5024}
5025
5026/**
5027 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
5028 * @hdd_ipa: Global HDD IPA context
5029 *
5030 * Return: None
5031 */
5032static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
5033{
5034 int ret = 0, i;
Yun Parkd9c528e2017-08-30 16:34:57 -07005035 uint32_t max_desc_cnt;
Yun Park52b2b992016-09-22 15:49:51 -07005036 struct hdd_ipa_tx_desc *tmp_desc;
Yun Park6c86a662017-10-05 16:09:15 -07005037 qdf_ipa_rx_data_t *ipa_tx_desc;
Yun Park52b2b992016-09-22 15:49:51 -07005038
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005039 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
5040 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
Yun Park9281cb72017-11-30 11:14:30 -08005041 ret = qdf_ipa_teardown_sys_pipe(
5042 hdd_ipa->sys_pipe[i].conn_hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005043 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305044 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005045 ret);
5046
5047 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
5048 }
5049 }
Yun Park52b2b992016-09-22 15:49:51 -07005050
5051 if (hdd_ipa->tx_desc_list) {
Yun Parkd9c528e2017-08-30 16:34:57 -07005052 max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
5053
Yun Park52b2b992016-09-22 15:49:51 -07005054 qdf_spin_lock_bh(&hdd_ipa->q_lock);
Yun Parkd9c528e2017-08-30 16:34:57 -07005055 for (i = 0; i < max_desc_cnt; i++) {
Yun Park52b2b992016-09-22 15:49:51 -07005056 tmp_desc = hdd_ipa->tx_desc_list + i;
5057 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
5058 if (ipa_tx_desc)
5059 ipa_free_skb(ipa_tx_desc);
5060 }
5061 tmp_desc = hdd_ipa->tx_desc_list;
5062 hdd_ipa->tx_desc_list = NULL;
5063 hdd_ipa->stats.num_tx_desc_q_cnt = 0;
5064 hdd_ipa->stats.num_tx_desc_error = 0;
5065 qdf_spin_unlock_bh(&hdd_ipa->q_lock);
5066 qdf_mem_free(tmp_desc);
5067 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005068}
5069
5070/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005071 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
5072 * @iface_context: interface-specific IPA context
5073 *
5074 * Return: None
5075 */
5076static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
5077{
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005078 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07005079
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005080 if (iface_context == NULL)
5081 return;
Orhan K AKYILDIZ3332be32017-05-31 15:36:31 -07005082 if (iface_context->adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
5083 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
5084 "%s: bad adapter(%pK).magic(%d)!",
5085 __func__, iface_context->adapter,
5086 iface_context->adapter->magic);
5087 return;
5088 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005089
Yun Parkb4f591d2017-03-29 15:51:01 -07005090 cdp_ipa_cleanup_iface(cds_get_context(QDF_MODULE_ID_SOC),
5091 iface_context->adapter->dev->name,
5092 hdd_ipa_is_ipv6_enabled(iface_context->hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005093
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305094 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005095 iface_context->adapter->ipa_context = NULL;
5096 iface_context->adapter = NULL;
5097 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305098 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005099 iface_context->ifa_address = 0;
5100 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305101 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005102 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05305103 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005104 }
5105 iface_context->hdd_ipa->num_iface--;
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005106 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005107 iface_context->hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005108}
5109
5110/**
5111 * hdd_ipa_setup_iface() - Setup IPA on a given interface
5112 * @hdd_ipa: HDD IPA global context
5113 * @adapter: Interface upon which IPA is being setup
5114 * @sta_id: Station ID of the API instance
5115 *
5116 * Return: 0 on success, negative errno value on error
5117 */
5118static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
Jeff Johnson49d45e62017-08-29 14:30:42 -07005119 struct hdd_adapter *adapter, uint8_t sta_id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005120{
5121 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park0dad1002017-07-14 14:57:01 -07005122 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
5123 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005124 void *tl_context = NULL;
5125 int i, ret = 0;
5126
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005127 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
Yun Parkfec73dc2017-09-06 10:40:07 -07005128
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005129 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
5130 * channel change indication. Since these indications are sent by lower
5131 * layer as SAP updates and IPA doesn't have to do anything for these
5132 * updates so ignoring!
5133 */
Krunal Sonibe766b02016-03-10 13:00:44 -08005134 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005135 return 0;
5136
5137 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5138 if (hdd_ipa->iface_context[i].adapter == NULL) {
5139 iface_context = &(hdd_ipa->iface_context[i]);
5140 break;
5141 }
5142 }
5143
5144 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305145 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005146 "All the IPA interfaces are in use");
5147 ret = -ENOMEM;
5148 goto end;
5149 }
5150
5151 adapter->ipa_context = iface_context;
5152 iface_context->adapter = adapter;
5153 iface_context->sta_id = sta_id;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08005154 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
Yun Park0dad1002017-07-14 14:57:01 -07005155 soc, (struct cdp_pdev *)pdev, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005156 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305157 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005158 "Not able to get TL context sta_id: %d", sta_id);
5159 ret = -EINVAL;
5160 goto end;
5161 }
5162
5163 iface_context->tl_context = tl_context;
5164
Yun Parkb4f591d2017-03-29 15:51:01 -07005165 ret = cdp_ipa_setup_iface(cds_get_context(QDF_MODULE_ID_SOC),
5166 adapter->dev->name, adapter->dev->dev_addr,
5167 iface_context->prod_client,
5168 iface_context->cons_client,
Jeff Johnson1b780e42017-10-31 14:11:45 -07005169 adapter->session_id,
Yun Parkb4f591d2017-03-29 15:51:01 -07005170 hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005171 if (ret)
5172 goto end;
5173
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005174 hdd_ipa->num_iface++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005175
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005176 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: num_iface=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005177 hdd_ipa->num_iface);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005178 return ret;
5179
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005180end:
5181 if (iface_context)
5182 hdd_ipa_cleanup_iface(iface_context);
5183 return ret;
5184}
5185
Yun Parka27049a2016-10-11 12:30:49 -07005186#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005187/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005188 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Jeff Johnson4929cd92017-10-06 19:21:57 -07005189 * @hdd_ctx: HDD context
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005190 * @mcc_mode: 0=MCC/1=SCC
5191 *
5192 * Return: 0 on success, negative errno value on error
5193 */
Jeff Johnson4929cd92017-10-06 19:21:57 -07005194static int __hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx,
5195 bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005196{
Jeff Johnson089d0432017-10-02 13:27:21 -07005197 struct hdd_adapter *adapter;
Yun Park6c86a662017-10-05 16:09:15 -07005198 qdf_ipa_msg_meta_t meta;
5199 qdf_ipa_wlan_msg_t *msg;
5200
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005201 int ret;
5202
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005203 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005204 return -EINVAL;
5205
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005206 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
5207 return -EINVAL;
5208
5209 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005210 /* Flush TxRx queue for each adapter before switch to SCC */
Dustin Brown920397d2017-12-13 16:27:50 -08005211 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson089d0432017-10-02 13:27:21 -07005212 if (adapter->device_mode == QDF_STA_MODE ||
5213 adapter->device_mode == QDF_SAP_MODE) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005214 hdd_debug("MCC->SCC: Flush TxRx queue(d_mode=%d)",
Jeff Johnson089d0432017-10-02 13:27:21 -07005215 adapter->device_mode);
5216 hdd_deinit_tx_rx(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005217 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005218 }
5219 }
5220
5221 /* Send SCC/MCC Switching event to IPA */
Yun Park6c86a662017-10-05 16:09:15 -07005222 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
5223 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005224 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005225 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005226 return -ENOMEM;
5227 }
5228
Yun Park6c86a662017-10-05 16:09:15 -07005229 QDF_IPA_MSG_META_MSG_TYPE(&meta) = mcc_mode ?
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005230 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Yun Park6c86a662017-10-05 16:09:15 -07005231 hdd_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005232
Yun Park6c86a662017-10-05 16:09:15 -07005233 ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005234
5235 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08005236 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Yun Park6c86a662017-10-05 16:09:15 -07005237 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305238 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005239 }
5240
5241 return ret;
5242}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005243
5244/**
5245 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
5246 * @mcc_mode: 0=MCC/1=SCC
5247 *
5248 * Return: 0 on success, negative errno value on error
5249 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005250int hdd_ipa_send_mcc_scc_msg(struct hdd_context *hdd_ctx, bool mcc_mode)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005251{
5252 int ret;
5253
5254 cds_ssr_protect(__func__);
5255 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
5256 cds_ssr_unprotect(__func__);
5257
5258 return ret;
5259}
Yun Parka27049a2016-10-11 12:30:49 -07005260#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005261
5262/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07005263 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
5264 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
5265 *
Yun Park6c86a662017-10-05 16:09:15 -07005266 * Return: qdf_ipa_wlan_event representing the hdd_ipa_wlan_event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005267 */
Yun Park6c86a662017-10-05 16:09:15 -07005268static qdf_ipa_wlan_event_t
Mohit Khannafa99aea2016-05-12 21:43:13 -07005269hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
5270{
Yun Park6c86a662017-10-05 16:09:15 -07005271 qdf_ipa_wlan_event_t ipa_event;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005272
5273 switch (hdd_ipa_event_type) {
5274 case HDD_IPA_CLIENT_CONNECT:
5275 ipa_event = WLAN_CLIENT_CONNECT;
5276 break;
5277 case HDD_IPA_CLIENT_DISCONNECT:
5278 ipa_event = WLAN_CLIENT_DISCONNECT;
5279 break;
5280 case HDD_IPA_AP_CONNECT:
5281 ipa_event = WLAN_AP_CONNECT;
5282 break;
5283 case HDD_IPA_AP_DISCONNECT:
5284 ipa_event = WLAN_AP_DISCONNECT;
5285 break;
5286 case HDD_IPA_STA_CONNECT:
5287 ipa_event = WLAN_STA_CONNECT;
5288 break;
5289 case HDD_IPA_STA_DISCONNECT:
5290 ipa_event = WLAN_STA_DISCONNECT;
5291 break;
5292 case HDD_IPA_CLIENT_CONNECT_EX:
5293 ipa_event = WLAN_CLIENT_CONNECT_EX;
5294 break;
5295 case HDD_IPA_WLAN_EVENT_MAX:
5296 default:
5297 ipa_event = IPA_WLAN_EVENT_MAX;
5298 break;
5299 }
5300 return ipa_event;
5301
5302}
5303
5304/**
5305 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005306 * @adapter: adapter upon which the event was received
5307 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07005308 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005309 * @mac_address: MAC address associated with the event
5310 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07005311 * This function is meant to be called from within wlan_hdd_ipa.c
5312 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005313 * Return: 0 on success, negative errno value on error
5314 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005315static int __hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Yun Park6c86a662017-10-05 16:09:15 -07005316 qdf_ipa_wlan_event_t type, uint8_t *mac_addr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005317{
5318 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Yun Park6c86a662017-10-05 16:09:15 -07005319 qdf_ipa_msg_meta_t meta;
5320 qdf_ipa_wlan_msg_t *msg;
5321 qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005322 int ret;
5323
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005324 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: EVT: %s, MAC: %pM, sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005325 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
5326 mac_addr, sta_id);
5327
5328 if (type >= IPA_WLAN_EVENT_MAX)
5329 return -EINVAL;
5330
5331 if (WARN_ON(is_zero_ether_addr(mac_addr)))
5332 return -EINVAL;
5333
5334 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305335 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005336 return -EINVAL;
5337 }
5338
5339 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5340 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08005341 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005342 return 0;
5343 }
5344
5345 /*
5346 * During IPA UC resource loading/unloading new events can be issued.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005347 */
Yun Park777d7242017-03-30 15:38:33 -07005348 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
5349 (hdd_ipa->resource_loading || hdd_ipa->resource_unloading)) {
5350 unsigned int pending_event_count;
5351 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08005352
Yun Park46255682017-10-09 15:56:34 -07005353 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park777d7242017-03-30 15:38:33 -07005354 "%s:IPA resource %s inprogress",
5355 hdd_ipa_wlan_event_to_str(type),
5356 hdd_ipa->resource_loading ?
5357 "load" : "unload");
5358
5359 /* Wait until completion of the long/unloading */
5360 ret = wait_for_completion_timeout(&hdd_ipa->ipa_resource_comp,
5361 msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME));
5362 if (!ret) {
5363 /*
5364 * If timed out, store the events separately and
5365 * handle them later.
5366 */
Yun Park46255682017-10-09 15:56:34 -07005367 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park777d7242017-03-30 15:38:33 -07005368 "IPA resource %s timed out",
5369 hdd_ipa->resource_loading ?
5370 "load" : "unload");
Yun Park7c4f31b2016-11-30 10:09:21 -08005371
Yun Park777d7242017-03-30 15:38:33 -07005372 if (hdd_ipa->resource_loading) {
5373 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08005374
Yun Park777d7242017-03-30 15:38:33 -07005375 pending_event_count =
Srinivas Girigowdac16ba6d2017-03-25 11:43:26 -07005376 qdf_list_size(&hdd_ipa->pending_event);
Yun Park777d7242017-03-30 15:38:33 -07005377 if (pending_event_count >=
5378 HDD_IPA_MAX_PENDING_EVENT_COUNT) {
5379 hdd_debug(
5380 "Reached max pending event count");
5381 qdf_list_remove_front(
5382 &hdd_ipa->pending_event,
5383 (qdf_list_node_t **)&pending_event);
5384 } else {
5385 pending_event =
5386 (struct ipa_uc_pending_event *)
5387 qdf_mem_malloc(sizeof(
5388 struct ipa_uc_pending_event));
5389 }
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005390
Yun Park777d7242017-03-30 15:38:33 -07005391 if (!pending_event) {
5392 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
5393 "Pending event memory alloc fail");
5394 qdf_mutex_release(&hdd_ipa->ipa_lock);
5395 return -ENOMEM;
5396 }
5397
5398 pending_event->adapter = adapter;
5399 pending_event->sta_id = sta_id;
5400 pending_event->type = type;
5401 qdf_mem_copy(pending_event->mac_addr,
5402 mac_addr, QDF_MAC_ADDR_SIZE);
5403 qdf_list_insert_back(&hdd_ipa->pending_event,
5404 &pending_event->node);
5405
Yun Park64c405e2017-01-10 22:35:51 -08005406 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005407 }
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07005408 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005409 }
Yun Park46255682017-10-09 15:56:34 -07005410 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Jeff Johnson4929cd92017-10-06 19:21:57 -07005411 "IPA resource %s completed",
5412 hdd_ipa->resource_loading ?
5413 "load" : "unload");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005414 }
5415
5416 hdd_ipa->stats.event[type]++;
5417
Yun Park6c86a662017-10-05 16:09:15 -07005418 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005419 switch (type) {
5420 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005421 qdf_mutex_acquire(&hdd_ipa->event_lock);
5422
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005423 /* STA already connected and without disconnect, connect again
5424 * This is Roaming scenario
5425 */
5426 if (hdd_ipa->sta_connected)
5427 hdd_ipa_cleanup_iface(adapter->ipa_context);
5428
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005429 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5430 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305431 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005432 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005433 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005434
Yun Park8f289c82016-10-18 16:38:21 -07005435 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5436 (hdd_ipa->sap_num_connected_sta > 0) &&
5437 !hdd_ipa->sta_connected) {
5438 qdf_mutex_release(&hdd_ipa->event_lock);
5439 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005440 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005441 qdf_mutex_acquire(&hdd_ipa->event_lock);
5442 }
5443
Jeff Johnson1b780e42017-10-31 14:11:45 -07005444 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005445 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005446 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005447
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005448 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07005449
5450 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005451
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005452 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005453 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005454 break;
5455
5456 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005457 qdf_mutex_acquire(&hdd_ipa->event_lock);
5458
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005459 /* For DFS channel we get two start_bss event (before and after
5460 * CAC). Also when ACS range includes both DFS and non DFS
5461 * channels, we could possibly change channel many times due to
5462 * RADAR detection and chosen channel may not be a DFS channels.
5463 * So dont return error here. Just discard the event.
5464 */
Yun Park8f289c82016-10-18 16:38:21 -07005465 if (adapter->ipa_context) {
5466 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005467 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07005468 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005469
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005470 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
5471 if (ret) {
Yun Park64c405e2017-01-10 22:35:51 -08005472 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005473 hdd_err("%s: Evt: %d, Interface setup failed",
Yun Park6c86a662017-10-05 16:09:15 -07005474 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005475 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07005476 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005477
Yun Park8f289c82016-10-18 16:38:21 -07005478 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5479 qdf_mutex_release(&hdd_ipa->event_lock);
5480 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005481 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005482 qdf_mutex_acquire(&hdd_ipa->event_lock);
5483 }
5484
Jeff Johnson1b780e42017-10-31 14:11:45 -07005485 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005486 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07005487 (adapter->ipa_context))->iface_id;
5488
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305489 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005490 break;
5491
5492 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305493 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005494
5495 if (!hdd_ipa->sta_connected) {
Yun Park64c405e2017-01-10 22:35:51 -08005496 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005497 hdd_err("%s: Evt: %d, STA already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005498 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005499 return -EINVAL;
5500 }
Yun Parka37592b2016-06-11 17:10:28 -07005501
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005502 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07005503
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005504 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005505 hdd_debug("%s: IPA UC OFFLOAD NOT ENABLED",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005506 msg_ex->name);
5507 } else {
5508 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Park3b7152b2017-08-25 08:33:37 -07005509 if ((1 == hdd_ipa->num_iface) &&
Yun Parka37592b2016-06-11 17:10:28 -07005510 (HDD_IPA_UC_NUM_WDI_PIPE ==
Yun Park3b7152b2017-08-25 08:33:37 -07005511 hdd_ipa->activated_fw_pipe) &&
5512 !hdd_ipa->ipa_pipes_down)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005513 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005514 }
5515
Yun Park74127cf2016-09-18 11:22:41 -07005516 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
5517 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07005518 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005519 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005520 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005521 qdf_mutex_acquire(&hdd_ipa->event_lock);
Jeff Johnson1b780e42017-10-31 14:11:45 -07005522 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005523 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005524 }
5525
Yun Park8f289c82016-10-18 16:38:21 -07005526 hdd_ipa_cleanup_iface(adapter->ipa_context);
5527
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305528 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkfec73dc2017-09-06 10:40:07 -07005529
Kiran Kumar Lokere1d411bb2017-11-29 15:24:05 -08005530 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "sta_connected=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005531 hdd_ipa->sta_connected);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005532 break;
5533
5534 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07005535 qdf_mutex_acquire(&hdd_ipa->event_lock);
5536
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005537 if (!adapter->ipa_context) {
Yun Park64c405e2017-01-10 22:35:51 -08005538 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parkb187d542016-11-14 18:10:04 -08005539 hdd_err("%s: Evt: %d, SAP already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005540 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005541 return -EINVAL;
5542 }
5543
Yun Park3b7152b2017-08-25 08:33:37 -07005544 if ((1 == hdd_ipa->num_iface) &&
5545 (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
5546 !hdd_ipa->ipa_pipes_down) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08005547 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005548 /*
5549 * We disable WDI pipes directly here since
5550 * IPA_OPCODE_TX/RX_SUSPEND message will not be
5551 * processed when unloading WLAN driver is in
5552 * progress
5553 */
5554 hdd_ipa_uc_disable_pipes(hdd_ipa);
5555 } else {
Yun Park199c2ed2017-10-02 11:24:22 -07005556 /*
5557 * This shouldn't happen :
5558 * No interface left but WDI pipes are still
5559 * active - force close WDI pipes
5560 */
5561 WARN_ON(1);
5562 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
5563 "No interface left but WDI pipes are still active - force close WDI pipes");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005564 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5565 }
5566 }
5567
5568 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07005569 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005570 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005571 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005572 qdf_mutex_acquire(&hdd_ipa->event_lock);
Jeff Johnson1b780e42017-10-31 14:11:45 -07005573 hdd_ipa->vdev_to_iface[adapter->session_id] =
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005574 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005575 }
Yun Parka37592b2016-06-11 17:10:28 -07005576
Yun Park8f289c82016-10-18 16:38:21 -07005577 hdd_ipa_cleanup_iface(adapter->ipa_context);
5578
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305579 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005580 break;
5581
5582 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005583 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005584 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005585 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305586 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005587 return 0;
5588 }
5589
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305590 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005591 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
5592 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07005593 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305594 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005595 "%s: STA ID %d found, not valid",
5596 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005597 return 0;
5598 }
Yun Park312f71a2015-12-08 10:22:42 -08005599
5600 /* Enable IPA UC Data PIPEs when first STA connected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005601 if (hdd_ipa->sap_num_connected_sta == 0 &&
5602 hdd_ipa->uc_loaded == true) {
Yun Parka37592b2016-06-11 17:10:28 -07005603 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005604 hdd_ipa->sta_connected) {
5605 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005606 hdd_ipa_uc_offload_enable_disable(
5607 hdd_get_adapter(hdd_ipa->hdd_ctx,
5608 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005609 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07005610 qdf_mutex_acquire(&hdd_ipa->event_lock);
5611 }
Yun Parka37592b2016-06-11 17:10:28 -07005612
Yun Park312f71a2015-12-08 10:22:42 -08005613 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
5614 if (ret) {
Yun Park46255682017-10-09 15:56:34 -07005615 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park312f71a2015-12-08 10:22:42 -08005616 "%s: handle 1st con ret %d",
5617 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07005618
5619 if (hdd_ipa_uc_sta_is_enabled(
5620 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07005621 hdd_ipa->sta_connected) {
5622 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07005623 hdd_ipa_uc_offload_enable_disable(
5624 hdd_get_adapter(
5625 hdd_ipa->hdd_ctx,
5626 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005627 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07005628 } else {
5629 qdf_mutex_release(&hdd_ipa->event_lock);
5630 }
Yun Parka37592b2016-06-11 17:10:28 -07005631
Yun Park312f71a2015-12-08 10:22:42 -08005632 return ret;
5633 }
5634 }
5635
5636 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08005637
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305638 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005639
Yun Park6c86a662017-10-05 16:09:15 -07005640 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
5641 QDF_IPA_MSG_META_MSG_LEN(&meta) =
5642 (sizeof(qdf_ipa_wlan_msg_ex_t) +
5643 sizeof(qdf_ipa_wlan_hdr_attrib_val_t));
5644 msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005645
5646 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305647 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005648 "msg_ex allocation failed");
5649 return -ENOMEM;
5650 }
5651 strlcpy(msg_ex->name, adapter->dev->name,
5652 IPA_RESOURCE_NAME_MAX);
5653 msg_ex->num_of_attribs = 1;
5654 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
5655 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5656 msg_ex->attribs[0].offset =
5657 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
5658 } else {
5659 msg_ex->attribs[0].offset =
5660 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
5661 }
5662 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
5663 IPA_MAC_ADDR_SIZE);
5664
5665 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
5666
5667 if (ret) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005668 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05305669 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305670 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005671 return ret;
5672 }
5673 hdd_ipa->stats.num_send_msg++;
Yun Parkfec73dc2017-09-06 10:40:07 -07005674
Yun Park199c2ed2017-10-02 11:24:22 -07005675 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005676 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005677 return ret;
5678
5679 case WLAN_CLIENT_DISCONNECT:
5680 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005681 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005682 "%s: IPA UC OFFLOAD NOT ENABLED",
5683 msg_ex->name);
5684 return 0;
5685 }
5686
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305687 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Park73ea8bb2017-08-25 07:27:39 -07005688 if (!hdd_ipa->sap_num_connected_sta) {
5689 qdf_mutex_release(&hdd_ipa->event_lock);
5690 hdd_err("%s: Evt: %d, Client already disconnected",
Yun Park6c86a662017-10-05 16:09:15 -07005691 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
Yun Park73ea8bb2017-08-25 07:27:39 -07005692 return 0;
5693 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005694 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Yun Park64c405e2017-01-10 22:35:51 -08005695 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305696 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005697 "%s: STA ID %d NOT found, not valid",
5698 msg_ex->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005699 return 0;
5700 }
5701 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07005702
Yun Park9b5030f2016-11-08 12:02:37 -08005703 /* Disable IPA UC TX PIPE when last STA disconnected */
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005704 if (!hdd_ipa->sap_num_connected_sta &&
5705 hdd_ipa->uc_loaded == true) {
Yun Park9b5030f2016-11-08 12:02:37 -08005706 if ((false == hdd_ipa->resource_unloading)
5707 && (HDD_IPA_UC_NUM_WDI_PIPE ==
Govind Singhb78a75c2017-02-21 17:37:11 +05305708 hdd_ipa->activated_fw_pipe) &&
5709 !hdd_ipa->ipa_pipes_down) {
Yun Park9b5030f2016-11-08 12:02:37 -08005710 hdd_ipa_uc_handle_last_discon(hdd_ipa);
5711 }
5712
Yun Park9b5030f2016-11-08 12:02:37 -08005713 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
jiad9d472c92017-07-28 14:05:31 +08005714 hdd_ipa->sta_connected) {
5715 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005716 hdd_ipa_uc_offload_enable_disable(
5717 hdd_get_adapter(hdd_ipa->hdd_ctx,
5718 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005719 SIR_STA_RX_DATA_OFFLOAD, false);
jiad9d472c92017-07-28 14:05:31 +08005720 } else {
5721 qdf_mutex_release(&hdd_ipa->event_lock);
5722 }
Yun Park8f289c82016-10-18 16:38:21 -07005723 } else {
5724 qdf_mutex_release(&hdd_ipa->event_lock);
5725 }
Yun Parkfec73dc2017-09-06 10:40:07 -07005726
Yun Park199c2ed2017-10-02 11:24:22 -07005727 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "sap_num_connected_sta=%d",
Yun Parkfec73dc2017-09-06 10:40:07 -07005728 hdd_ipa->sap_num_connected_sta);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005729 break;
5730
5731 default:
5732 return 0;
5733 }
5734
Yun Park6c86a662017-10-05 16:09:15 -07005735 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
5736 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005737 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305738 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005739 return -ENOMEM;
5740 }
5741
Yun Park6c86a662017-10-05 16:09:15 -07005742 QDF_IPA_MSG_META_MSG_TYPE(&meta) = type;
5743 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), adapter->dev->name,
5744 IPA_RESOURCE_NAME_MAX);
5745 memcpy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, ETH_ALEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005746
Srinivas Girigowda97852372017-03-06 16:52:59 -08005747 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d",
Yun Park6c86a662017-10-05 16:09:15 -07005748 QDF_IPA_WLAN_MSG_NAME(msg),
5749 QDF_IPA_MSG_META_MSG_TYPE(&meta));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005750
5751 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
5752
5753 if (ret) {
Yun Parkb187d542016-11-14 18:10:04 -08005754 hdd_err("%s: Evt: %d fail:%d",
Yun Park6c86a662017-10-05 16:09:15 -07005755 QDF_IPA_WLAN_MSG_NAME(msg),
5756 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305757 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005758 return ret;
5759 }
5760
5761 hdd_ipa->stats.num_send_msg++;
5762
5763end:
5764 return ret;
5765}
5766
5767/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005768 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07005769 * @adapter: adapter upon which the event was received
5770 * @sta_id: station id for the event
5771 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
5772 * @mac_address: MAC address associated with the event
5773 *
5774 * This function is meant to be called from outside of wlan_hdd_ipa.c.
5775 *
5776 * Return: 0 on success, negative errno value on error
5777 */
Jeff Johnson49d45e62017-08-29 14:30:42 -07005778int hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005779 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
5780{
Yun Park6c86a662017-10-05 16:09:15 -07005781 qdf_ipa_wlan_event_t type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005782 int ret = 0;
5783
5784 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005785
Leo Changa202b522016-10-14 16:13:50 -07005786 /* Data path offload only support for STA and SAP mode */
5787 if ((QDF_STA_MODE == adapter->device_mode) ||
5788 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005789 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07005790
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005791 cds_ssr_unprotect(__func__);
5792
5793 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07005794}
5795
5796/**
5797 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
5798 * @hdd_ipa: Global HDD IPA context
5799 *
5800 * Return: None
5801 */
5802static void
5803hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
5804{
5805 unsigned int pending_event_count;
5806 struct ipa_uc_pending_event *pending_event = NULL;
5807
5808 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
Srinivas Girigowda97852372017-03-06 16:52:59 -08005809 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07005810 "Pending Event Count %d", pending_event_count);
Mohit Khannafa99aea2016-05-12 21:43:13 -07005811 if (!pending_event_count) {
Srinivas Girigowda97852372017-03-06 16:52:59 -08005812 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Yun Park46255682017-10-09 15:56:34 -07005813 "No Pending Event");
Mohit Khannafa99aea2016-05-12 21:43:13 -07005814 return;
5815 }
5816
5817 qdf_list_remove_front(&hdd_ipa->pending_event,
5818 (qdf_list_node_t **)&pending_event);
5819 while (pending_event != NULL) {
5820 __hdd_ipa_wlan_evt(pending_event->adapter,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005821 pending_event->sta_id,
Will Huang0ca39e22017-10-24 14:32:57 +08005822 pending_event->type,
Mohit Khannafa99aea2016-05-12 21:43:13 -07005823 pending_event->mac_addr);
5824 qdf_mem_free(pending_event);
5825 pending_event = NULL;
5826 qdf_list_remove_front(&hdd_ipa->pending_event,
5827 (qdf_list_node_t **)&pending_event);
5828 }
5829}
5830
5831/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005832 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
5833 * @state: IPA RM state value
5834 *
5835 * Return: ASCII string representing the IPA RM state
5836 */
5837static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
5838{
5839 switch (state) {
5840 case HDD_IPA_RM_RELEASED:
5841 return "RELEASED";
5842 case HDD_IPA_RM_GRANT_PENDING:
5843 return "GRANT_PENDING";
5844 case HDD_IPA_RM_GRANTED:
5845 return "GRANTED";
5846 }
5847
5848 return "UNKNOWN";
5849}
5850
5851/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005852 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005853 * @hdd_ctx: HDD global context
5854 *
5855 * Allocate hdd_ipa resources, ipa pipe resource and register
5856 * wlan interface with IPA module.
5857 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305858 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005859 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07005860static QDF_STATUS __hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005861{
5862 struct hdd_ipa_priv *hdd_ipa = NULL;
5863 int ret, i;
5864 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Parkbaa62862017-01-18 13:43:34 -08005865 struct ol_txrx_pdev_t *pdev = NULL;
Yun Park6c86a662017-10-05 16:09:15 -07005866 qdf_ipa_rm_perf_profile_t profile;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005867
5868 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305869 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005870
Yun Park199c2ed2017-10-02 11:24:22 -07005871 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "enter");
5872
Yun Parkbaa62862017-01-18 13:43:34 -08005873 pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Yun Park7f171ab2016-07-29 15:44:22 -07005874 if (!pdev) {
5875 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
5876 goto fail_return;
5877 }
5878
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305879 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005880 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05305881 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08005882 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005883 }
5884
5885 hdd_ctx->hdd_ipa = hdd_ipa;
5886 ghdd_ipa = hdd_ipa;
5887 hdd_ipa->hdd_ctx = hdd_ctx;
5888 hdd_ipa->num_iface = 0;
5889
5890 /* Create the interface context */
5891 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
5892 iface_context = &hdd_ipa->iface_context[i];
5893 iface_context->hdd_ipa = hdd_ipa;
5894 iface_context->cons_client =
5895 hdd_ipa_adapter_2_client[i].cons_client;
5896 iface_context->prod_client =
5897 hdd_ipa_adapter_2_client[i].prod_client;
5898 iface_context->iface_id = i;
5899 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305900 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08005901 }
5902 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08005903 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
5904 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005905 }
5906
Leo Chang69c39692016-10-12 20:11:12 -07005907 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305908 qdf_spinlock_create(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07005909 qdf_spinlock_create(&hdd_ipa->q_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05305910 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005911 qdf_list_create(&hdd_ipa->pending_event, 1000);
5912 qdf_mutex_create(&hdd_ipa->event_lock);
5913 qdf_mutex_create(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005914
5915 ret = hdd_ipa_setup_rm(hdd_ipa);
5916 if (ret)
5917 goto fail_setup_rm;
5918
Yun Park9281cb72017-11-30 11:14:30 -08005919 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++)
5920 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
5921 sizeof(struct hdd_ipa_sys_pipe));
5922
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005923 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
5924 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305925 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005926 hdd_ipa->sap_num_connected_sta = 0;
5927 hdd_ipa->ipa_tx_packets_diff = 0;
5928 hdd_ipa->ipa_rx_packets_diff = 0;
5929 hdd_ipa->ipa_p_tx_packets = 0;
5930 hdd_ipa->ipa_p_rx_packets = 0;
5931 hdd_ipa->resource_loading = false;
5932 hdd_ipa->resource_unloading = false;
5933 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07005934 hdd_ipa->ipa_pipes_down = true;
Manikandan Mohancd64c0b2017-03-08 13:00:24 -08005935 hdd_ipa->wdi_enabled = false;
Yun Park9281cb72017-11-30 11:14:30 -08005936 /* Setup IPA system pipes */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005937 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
5938 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5939 if (ret)
5940 goto fail_create_sys_pipe;
5941 }
Manikandan Mohan153a4c32017-02-16 15:04:30 -08005942 if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
5943 goto fail_create_sys_pipe;
Manikandan Mohan2e803a02017-02-14 14:57:53 -08005944
5945 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
5946 hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
5947 hdd_ipa_uc_fw_op_event_handler);
5948 hdd_ipa->uc_op_work[i].msg = NULL;
5949 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005950 } else {
5951 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
5952 if (ret)
5953 goto fail_create_sys_pipe;
5954 }
5955
Yun Park66f24c42017-03-20 10:39:47 -07005956 /* When IPA clock scaling is disabled, initialze maximum clock */
5957 if (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)) {
5958 profile.max_supported_bandwidth_mbps = 800;
5959 hdd_debug("IPA clock scaling is disabled.");
5960 hdd_debug("Set initial CONS/PROD perf: %d",
5961 profile.max_supported_bandwidth_mbps);
5962 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
5963 &profile);
5964 if (ret) {
5965 hdd_err("RM CONS set perf profile failed: %d", ret);
5966 goto fail_create_sys_pipe;
5967 }
5968
5969 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
5970 &profile);
5971 if (ret) {
5972 hdd_err("RM PROD set perf profile failed: %d", ret);
5973 goto fail_create_sys_pipe;
5974 }
5975 }
5976
Yun Park777d7242017-03-30 15:38:33 -07005977 init_completion(&hdd_ipa->ipa_resource_comp);
5978
Yun Park199c2ed2017-10-02 11:24:22 -07005979 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: success");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305980 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005981
5982fail_create_sys_pipe:
5983 hdd_ipa_destroy_rm_resource(hdd_ipa);
5984fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05305985 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305986 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08005987 hdd_ctx->hdd_ipa = NULL;
5988 ghdd_ipa = NULL;
5989fail_return:
Yun Park199c2ed2017-10-02 11:24:22 -07005990 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: fail");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305991 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005992}
5993
5994/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07005995 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
5996 * @hdd_ctx: HDD global context
5997 *
5998 * Allocate hdd_ipa resources, ipa pipe resource and register
5999 * wlan interface with IPA module.
6000 *
6001 * Return: QDF_STATUS enumeration
6002 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07006003QDF_STATUS hdd_ipa_init(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006004{
6005 QDF_STATUS ret;
6006
6007 cds_ssr_protect(__func__);
6008 ret = __hdd_ipa_init(hdd_ctx);
6009 cds_ssr_unprotect(__func__);
6010
6011 return ret;
6012}
6013
Arun Khandavallicc544b32017-01-30 19:52:16 +05306014
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006015/**
Govind Singh1dab23b2017-08-12 13:31:00 +05306016 * __hdd_ipa_flush - flush IPA exception path SKB's
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006017 * @hdd_ctx: HDD global context
6018 *
Govind Singh1dab23b2017-08-12 13:31:00 +05306019 * Return: none
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006020 */
Govind Singh1dab23b2017-08-12 13:31:00 +05306021static void __hdd_ipa_flush(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006022{
6023 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
Nirav Shahcbc6d722016-03-01 16:24:53 +05306024 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006025 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
6026
6027 if (!hdd_ipa_is_enabled(hdd_ctx))
Govind Singh1dab23b2017-08-12 13:31:00 +05306028 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006029
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006030 cancel_work_sync(&hdd_ipa->pm_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006031
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306032 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006033
Nirav Shahcbc6d722016-03-01 16:24:53 +05306034 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
6035 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306036 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006037
6038 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Yun Parked827b42017-05-12 23:59:27 -07006039 if (pm_tx_cb->ipa_tx_desc)
6040 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
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 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306044 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Govind Singh1dab23b2017-08-12 13:31:00 +05306045}
6046
6047/**
6048 * __hdd_ipa_cleanup - IPA cleanup function
6049 * @hdd_ctx: HDD global context
6050 *
6051 * Return: QDF_STATUS enumeration
6052 */
6053static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
6054{
6055 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
6056 int i;
6057 struct hdd_ipa_iface_context *iface_context = NULL;
6058
6059 if (!hdd_ipa_is_enabled(hdd_ctx))
6060 return QDF_STATUS_SUCCESS;
6061
6062 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
6063 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
6064 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6065 }
6066
6067 /* Teardown IPA sys_pipe for MCC */
6068 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
6069 hdd_ipa_teardown_sys_pipe(hdd_ipa);
6070
6071 hdd_ipa_destroy_rm_resource(hdd_ipa);
6072
6073 __hdd_ipa_flush(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006074
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306075 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Yun Park52b2b992016-09-22 15:49:51 -07006076 qdf_spinlock_destroy(&hdd_ipa->q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006077
6078 /* destory the interface lock */
6079 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
6080 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306081 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006082 }
6083
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006084 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
Yun Park7e1f7c02017-01-05 08:19:49 -08006085 if (ipa_uc_dereg_rdyCB())
6086 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
6087 "UC Ready CB deregister fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006088 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05306089 qdf_mutex_destroy(&hdd_ipa->event_lock);
6090 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkd8fb1a82017-10-13 16:48:20 -07006091 qdf_list_destroy(&hdd_ipa->pending_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006092
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006093 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
6094 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
6095 hdd_ipa->uc_op_work[i].msg = NULL;
6096 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006097 }
6098
Anurag Chouhan600c3a02016-03-01 10:33:54 +05306099 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006100 hdd_ctx->hdd_ipa = NULL;
6101
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05306102 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006103}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006104
6105/**
Govind Singh1dab23b2017-08-12 13:31:00 +05306106 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_flush
6107 * @hdd_ctx: HDD global context
6108 *
6109 * Return: None
6110 */
6111void hdd_ipa_flush(struct hdd_context *hdd_ctx)
6112{
6113 cds_ssr_protect(__func__);
6114 __hdd_ipa_flush(hdd_ctx);
6115 cds_ssr_unprotect(__func__);
6116}
6117
6118/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006119 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
6120 * @hdd_ctx: HDD global context
6121 *
6122 * Return: QDF_STATUS enumeration
6123 */
Jeff Johnsondd595cb2017-08-28 11:58:09 -07006124QDF_STATUS hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
Prakash Dhavali412cdb02016-10-20 21:19:31 -07006125{
6126 QDF_STATUS ret;
6127
6128 cds_ssr_protect(__func__);
6129 ret = __hdd_ipa_cleanup(hdd_ctx);
6130 cds_ssr_unprotect(__func__);
6131
6132 return ret;
6133}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006134#endif /* IPA_OFFLOAD */