blob: 9f98ceb6b5e555878789b2126dcebde9e70f2ed4 [file] [log] [blame]
Skylar Changafc22fe2019-04-25 14:10:52 -07001/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
Amir Levy9659e592016-10-27 18:08:27 +03002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/clk.h>
14#include <linux/compat.h>
15#include <linux/device.h>
16#include <linux/dmapool.h>
17#include <linux/fs.h>
18#include <linux/genalloc.h>
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/mm.h>
22#include <linux/module.h>
23#include <linux/of.h>
24#include <linux/of_platform.h>
25#include <linux/platform_device.h>
26#include <linux/rbtree.h>
27#include <linux/of_gpio.h>
28#include <linux/uaccess.h>
29#include <linux/interrupt.h>
30#include <linux/msm-bus.h>
31#include <linux/msm-bus-board.h>
32#include <linux/netdevice.h>
33#include <linux/delay.h>
34#include <linux/msm_gsi.h>
Amir Levy9659e592016-10-27 18:08:27 +030035#include <linux/time.h>
36#include <linux/hashtable.h>
Amir Levyd9f51132016-11-14 16:55:35 +020037#include <linux/jhash.h>
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -040038#include <linux/pci.h>
Amir Levy9659e592016-10-27 18:08:27 +030039#include <soc/qcom/subsystem_restart.h>
40#include <soc/qcom/smem.h>
Gidon Studinski3021a6f2016-11-10 12:48:48 +020041#include <soc/qcom/scm.h>
Amir Levy635bced2016-12-19 09:20:42 +020042#include <asm/cacheflush.h>
Gidon Studinski3021a6f2016-11-10 12:48:48 +020043
44#ifdef CONFIG_ARM64
45
46/* Outer caches unsupported on ARM64 platforms */
47#define outer_flush_range(x, y)
48#define __cpuc_flush_dcache_area __flush_dcache_area
49
50#endif
51
Amir Levy9659e592016-10-27 18:08:27 +030052#define IPA_SUBSYSTEM_NAME "ipa_fws"
53#include "ipa_i.h"
54#include "../ipa_rm_i.h"
55#include "ipahal/ipahal.h"
56#include "ipahal/ipahal_fltrt.h"
57
58#define CREATE_TRACE_POINTS
59#include "ipa_trace.h"
60
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -040061/*
62 * The following for adding code (ie. for EMULATION) not found on x86.
63 */
64#if IPA_EMULATION_COMPILE == 1
65# include "ipa_emulation_stubs.h"
66#endif
Amir Levy9659e592016-10-27 18:08:27 +030067
68#ifdef CONFIG_COMPAT
Amir Levy9659e592016-10-27 18:08:27 +030069/**
70 * struct ipa3_ioc_nat_alloc_mem32 - nat table memory allocation
71 * properties
72 * @dev_name: input parameter, the name of table
73 * @size: input parameter, size of table in bytes
74 * @offset: output parameter, offset into page in case of system memory
75 */
76struct ipa3_ioc_nat_alloc_mem32 {
77 char dev_name[IPA_RESOURCE_NAME_MAX];
78 compat_size_t size;
79 compat_off_t offset;
80};
Amir Levy479cfdd2017-10-26 12:23:14 +030081
82/**
83 * struct ipa_ioc_nat_ipv6ct_table_alloc32 - table memory allocation
84 * properties
85 * @size: input parameter, size of table in bytes
86 * @offset: output parameter, offset into page in case of system memory
87 */
88struct ipa_ioc_nat_ipv6ct_table_alloc32 {
89 compat_size_t size;
90 compat_off_t offset;
91};
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -040092#endif /* #ifdef CONFIG_COMPAT */
Amir Levy9659e592016-10-27 18:08:27 +030093
Gidon Studinski3021a6f2016-11-10 12:48:48 +020094#define IPA_TZ_UNLOCK_ATTRIBUTE 0x0C0311
95#define TZ_MEM_PROTECT_REGION_ID 0x10
96
97struct tz_smmu_ipa_protect_region_iovec_s {
98 u64 input_addr;
99 u64 output_addr;
100 u64 size;
101 u32 attr;
102} __packed;
103
104struct tz_smmu_ipa_protect_region_s {
105 phys_addr_t iovec_buf;
106 u32 size_bytes;
107} __packed;
108
Amir Levy9659e592016-10-27 18:08:27 +0300109static void ipa3_start_tag_process(struct work_struct *work);
110static DECLARE_WORK(ipa3_tag_work, ipa3_start_tag_process);
111
Amir Levya59ed3f2017-03-05 17:30:55 +0200112static void ipa3_transport_release_resource(struct work_struct *work);
113static DECLARE_DELAYED_WORK(ipa3_transport_release_resource_work,
114 ipa3_transport_release_resource);
Amir Levy9659e592016-10-27 18:08:27 +0300115static void ipa_gsi_notify_cb(struct gsi_per_notify *notify);
116
Skylar Changefc0a0f2018-03-29 11:17:40 -0700117static int ipa3_attach_to_smmu(void);
118static int ipa3_alloc_pkt_init(void);
119
Ghanim Fodia5f376a2017-10-17 18:14:53 +0300120static void ipa3_load_ipa_fw(struct work_struct *work);
121static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw);
Utkarsh Saxenaded78142017-05-03 14:04:30 +0530122
Skylar Chang242952b2017-07-20 15:04:05 -0700123static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work);
124static DECLARE_WORK(ipa_dec_clients_disable_clks_on_wq_work,
125 ipa_dec_clients_disable_clks_on_wq);
126
Amir Levy9659e592016-10-27 18:08:27 +0300127static struct ipa3_plat_drv_res ipa3_res = {0, };
Amir Levy9659e592016-10-27 18:08:27 +0300128
129static struct clk *ipa3_clk;
130
131struct ipa3_context *ipa3_ctx;
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -0400132
Amir Levy9659e592016-10-27 18:08:27 +0300133static struct {
Skylar Changefc0a0f2018-03-29 11:17:40 -0700134 bool present[IPA_SMMU_CB_MAX];
Amir Levy9659e592016-10-27 18:08:27 +0300135 bool arm_smmu;
Amir Levy9659e592016-10-27 18:08:27 +0300136 bool fast_map;
Michael Adisumarta93e97522017-10-06 15:49:46 -0700137 bool s1_bypass_arr[IPA_SMMU_CB_MAX];
Amir Levy9659e592016-10-27 18:08:27 +0300138 bool use_64_bit_dma_mask;
139 u32 ipa_base;
140 u32 ipa_size;
141} smmu_info;
142
143static char *active_clients_table_buf;
144
145int ipa3_active_clients_log_print_buffer(char *buf, int size)
146{
147 int i;
148 int nbytes;
149 int cnt = 0;
150 int start_idx;
151 int end_idx;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700152 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +0300153
Skylar Chang69ae50e2017-07-31 13:13:29 -0700154 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300155 start_idx = (ipa3_ctx->ipa3_active_clients_logging.log_tail + 1) %
156 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES;
157 end_idx = ipa3_ctx->ipa3_active_clients_logging.log_head;
158 for (i = start_idx; i != end_idx;
159 i = (i + 1) % IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) {
160 nbytes = scnprintf(buf + cnt, size - cnt, "%s\n",
161 ipa3_ctx->ipa3_active_clients_logging
162 .log_buffer[i]);
163 cnt += nbytes;
164 }
Skylar Chang69ae50e2017-07-31 13:13:29 -0700165 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
166 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300167
168 return cnt;
169}
170
171int ipa3_active_clients_log_print_table(char *buf, int size)
172{
173 int i;
174 struct ipa3_active_client_htable_entry *iterator;
175 int cnt = 0;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700176 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +0300177
Skylar Chang69ae50e2017-07-31 13:13:29 -0700178 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300179 cnt = scnprintf(buf, size, "\n---- Active Clients Table ----\n");
180 hash_for_each(ipa3_ctx->ipa3_active_clients_logging.htable, i,
181 iterator, list) {
182 switch (iterator->type) {
183 case IPA3_ACTIVE_CLIENT_LOG_TYPE_EP:
184 cnt += scnprintf(buf + cnt, size - cnt,
185 "%-40s %-3d ENDPOINT\n",
186 iterator->id_string, iterator->count);
187 break;
188 case IPA3_ACTIVE_CLIENT_LOG_TYPE_SIMPLE:
189 cnt += scnprintf(buf + cnt, size - cnt,
190 "%-40s %-3d SIMPLE\n",
191 iterator->id_string, iterator->count);
192 break;
193 case IPA3_ACTIVE_CLIENT_LOG_TYPE_RESOURCE:
194 cnt += scnprintf(buf + cnt, size - cnt,
195 "%-40s %-3d RESOURCE\n",
196 iterator->id_string, iterator->count);
197 break;
198 case IPA3_ACTIVE_CLIENT_LOG_TYPE_SPECIAL:
199 cnt += scnprintf(buf + cnt, size - cnt,
200 "%-40s %-3d SPECIAL\n",
201 iterator->id_string, iterator->count);
202 break;
203 default:
204 IPAERR("Trying to print illegal active_clients type");
205 break;
206 }
207 }
208 cnt += scnprintf(buf + cnt, size - cnt,
209 "\nTotal active clients count: %d\n",
Skylar Chang242952b2017-07-20 15:04:05 -0700210 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
Skylar Chang69ae50e2017-07-31 13:13:29 -0700211 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
212 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300213
214 return cnt;
215}
216
Skylar Chang68c37d82018-04-07 16:42:36 -0700217static int ipa3_clean_modem_rule(void)
218{
219 struct ipa_install_fltr_rule_req_msg_v01 *req;
220 struct ipa_install_fltr_rule_req_ex_msg_v01 *req_ex;
221 int val = 0;
222
223 if (ipa3_ctx->ipa_hw_type < IPA_HW_v3_0) {
224 req = kzalloc(
225 sizeof(struct ipa_install_fltr_rule_req_msg_v01),
226 GFP_KERNEL);
227 if (!req) {
228 IPAERR("mem allocated failed!\n");
229 return -ENOMEM;
230 }
231 req->filter_spec_list_valid = false;
232 req->filter_spec_list_len = 0;
233 req->source_pipe_index_valid = 0;
234 val = ipa3_qmi_filter_request_send(req);
235 kfree(req);
236 } else {
237 req_ex = kzalloc(
238 sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01),
239 GFP_KERNEL);
240 if (!req_ex) {
241 IPAERR("mem allocated failed!\n");
242 return -ENOMEM;
243 }
244 req_ex->filter_spec_ex_list_valid = false;
245 req_ex->filter_spec_ex_list_len = 0;
246 req_ex->source_pipe_index_valid = 0;
247 val = ipa3_qmi_filter_request_ex_send(req_ex);
248 kfree(req_ex);
249 }
250
251 return val;
252}
253
Amir Levy9659e592016-10-27 18:08:27 +0300254static int ipa3_active_clients_panic_notifier(struct notifier_block *this,
255 unsigned long event, void *ptr)
256{
Amir Levy9659e592016-10-27 18:08:27 +0300257 ipa3_active_clients_log_print_table(active_clients_table_buf,
258 IPA3_ACTIVE_CLIENTS_TABLE_BUF_SIZE);
Michael Adisumartaedba22d2018-04-19 12:28:33 -0700259 IPAERR("%s\n", active_clients_table_buf);
Amir Levy9659e592016-10-27 18:08:27 +0300260
261 return NOTIFY_DONE;
262}
263
264static struct notifier_block ipa3_active_clients_panic_blk = {
265 .notifier_call = ipa3_active_clients_panic_notifier,
266};
267
268static int ipa3_active_clients_log_insert(const char *string)
269{
270 int head;
271 int tail;
272
273 if (!ipa3_ctx->ipa3_active_clients_logging.log_rdy)
274 return -EPERM;
275
276 head = ipa3_ctx->ipa3_active_clients_logging.log_head;
277 tail = ipa3_ctx->ipa3_active_clients_logging.log_tail;
278
279 memset(ipa3_ctx->ipa3_active_clients_logging.log_buffer[head], '_',
280 IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN);
281 strlcpy(ipa3_ctx->ipa3_active_clients_logging.log_buffer[head], string,
282 (size_t)IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN);
283 head = (head + 1) % IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES;
284 if (tail == head)
285 tail = (tail + 1) % IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES;
286
287 ipa3_ctx->ipa3_active_clients_logging.log_tail = tail;
288 ipa3_ctx->ipa3_active_clients_logging.log_head = head;
289
290 return 0;
291}
292
293static int ipa3_active_clients_log_init(void)
294{
295 int i;
296
Skylar Chang69ae50e2017-07-31 13:13:29 -0700297 spin_lock_init(&ipa3_ctx->ipa3_active_clients_logging.lock);
Amir Levy9659e592016-10-27 18:08:27 +0300298 ipa3_ctx->ipa3_active_clients_logging.log_buffer[0] = kzalloc(
299 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES *
300 sizeof(char[IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN]),
301 GFP_KERNEL);
302 active_clients_table_buf = kzalloc(sizeof(
303 char[IPA3_ACTIVE_CLIENTS_TABLE_BUF_SIZE]), GFP_KERNEL);
304 if (ipa3_ctx->ipa3_active_clients_logging.log_buffer == NULL) {
305 pr_err("Active Clients Logging memory allocation failed");
306 goto bail;
307 }
308 for (i = 0; i < IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; i++) {
309 ipa3_ctx->ipa3_active_clients_logging.log_buffer[i] =
310 ipa3_ctx->ipa3_active_clients_logging.log_buffer[0] +
311 (IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN * i);
312 }
313 ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
314 ipa3_ctx->ipa3_active_clients_logging.log_tail =
315 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
316 hash_init(ipa3_ctx->ipa3_active_clients_logging.htable);
317 atomic_notifier_chain_register(&panic_notifier_list,
318 &ipa3_active_clients_panic_blk);
319 ipa3_ctx->ipa3_active_clients_logging.log_rdy = 1;
320
321 return 0;
322
323bail:
324 return -ENOMEM;
325}
326
327void ipa3_active_clients_log_clear(void)
328{
Skylar Chang69ae50e2017-07-31 13:13:29 -0700329 unsigned long flags;
330
331 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300332 ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
333 ipa3_ctx->ipa3_active_clients_logging.log_tail =
334 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700335 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
336 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300337}
338
339static void ipa3_active_clients_log_destroy(void)
340{
Skylar Chang69ae50e2017-07-31 13:13:29 -0700341 unsigned long flags;
342
343 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300344 ipa3_ctx->ipa3_active_clients_logging.log_rdy = 0;
Ghanim Fodic48ba992017-12-24 19:28:38 +0200345 kfree(active_clients_table_buf);
346 active_clients_table_buf = NULL;
Amir Levy9659e592016-10-27 18:08:27 +0300347 kfree(ipa3_ctx->ipa3_active_clients_logging.log_buffer[0]);
348 ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
349 ipa3_ctx->ipa3_active_clients_logging.log_tail =
350 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700351 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
352 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300353}
354
Amir Levy9659e592016-10-27 18:08:27 +0300355static struct ipa_smmu_cb_ctx smmu_cb[IPA_SMMU_CB_MAX];
356
357struct iommu_domain *ipa3_get_smmu_domain(void)
358{
359 if (smmu_cb[IPA_SMMU_CB_AP].valid)
360 return smmu_cb[IPA_SMMU_CB_AP].mapping->domain;
361
362 IPAERR("CB not valid\n");
363
364 return NULL;
365}
366
367struct iommu_domain *ipa3_get_uc_smmu_domain(void)
368{
369 if (smmu_cb[IPA_SMMU_CB_UC].valid)
370 return smmu_cb[IPA_SMMU_CB_UC].mapping->domain;
371
372 IPAERR("CB not valid\n");
373
374 return NULL;
375}
376
377struct iommu_domain *ipa3_get_wlan_smmu_domain(void)
378{
379 if (smmu_cb[IPA_SMMU_CB_WLAN].valid)
380 return smmu_cb[IPA_SMMU_CB_WLAN].iommu;
381
382 IPAERR("CB not valid\n");
383
384 return NULL;
385}
386
Michael Adisumartab1bafa42018-04-16 16:48:10 -0700387struct iommu_domain *ipa3_get_smmu_domain_by_type(enum ipa_smmu_cb_type cb_type)
388{
389
390 if (cb_type == IPA_SMMU_CB_WLAN && smmu_cb[IPA_SMMU_CB_WLAN].valid)
391 return smmu_cb[IPA_SMMU_CB_WLAN].iommu;
392
393 if (smmu_cb[cb_type].valid)
394 return smmu_cb[cb_type].mapping->domain;
395
396 IPAERR("CB#%d not valid\n", cb_type);
397
398 return NULL;
399}
Amir Levy9659e592016-10-27 18:08:27 +0300400
401struct device *ipa3_get_dma_dev(void)
402{
403 return ipa3_ctx->pdev;
404}
405
406/**
Skylar Changefc0a0f2018-03-29 11:17:40 -0700407 * ipa3_get_smmu_ctx()- Return smmu context for the given cb_type
Amir Levy9659e592016-10-27 18:08:27 +0300408 *
409 * Return value: pointer to smmu context address
410 */
Skylar Changefc0a0f2018-03-29 11:17:40 -0700411struct ipa_smmu_cb_ctx *ipa3_get_smmu_ctx(enum ipa_smmu_cb_type cb_type)
Amir Levy9659e592016-10-27 18:08:27 +0300412{
Skylar Changefc0a0f2018-03-29 11:17:40 -0700413 return &smmu_cb[cb_type];
Amir Levy9659e592016-10-27 18:08:27 +0300414}
415
416static int ipa3_open(struct inode *inode, struct file *filp)
417{
Amir Levy9659e592016-10-27 18:08:27 +0300418 IPADBG_LOW("ENTER\n");
Skylar Changefc0a0f2018-03-29 11:17:40 -0700419 filp->private_data = ipa3_ctx;
Amir Levy9659e592016-10-27 18:08:27 +0300420
421 return 0;
422}
423
Amir Levy9659e592016-10-27 18:08:27 +0300424static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type)
425{
426 if (!buff) {
427 IPAERR("Null buffer\n");
428 return;
429 }
430
431 if (type != WAN_UPSTREAM_ROUTE_ADD &&
432 type != WAN_UPSTREAM_ROUTE_DEL &&
433 type != WAN_EMBMS_CONNECT) {
434 IPAERR("Wrong type given. buff %p type %d\n", buff, type);
435 return;
436 }
437
438 kfree(buff);
439}
440
Skylar Chang68c37d82018-04-07 16:42:36 -0700441static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type,
442 bool is_cache)
Amir Levy9659e592016-10-27 18:08:27 +0300443{
444 int retval;
445 struct ipa_wan_msg *wan_msg;
446 struct ipa_msg_meta msg_meta;
Mohammed Javid616bb992017-10-03 13:10:05 +0530447 struct ipa_wan_msg cache_wan_msg;
Amir Levy9659e592016-10-27 18:08:27 +0300448
449 wan_msg = kzalloc(sizeof(struct ipa_wan_msg), GFP_KERNEL);
450 if (!wan_msg) {
451 IPAERR("no memory\n");
452 return -ENOMEM;
453 }
454
Amir Levy479cfdd2017-10-26 12:23:14 +0300455 if (copy_from_user(wan_msg, (const void __user *)usr_param,
Amir Levy9659e592016-10-27 18:08:27 +0300456 sizeof(struct ipa_wan_msg))) {
457 kfree(wan_msg);
458 return -EFAULT;
459 }
460
Mohammed Javid616bb992017-10-03 13:10:05 +0530461 memcpy(&cache_wan_msg, wan_msg, sizeof(cache_wan_msg));
462
Amir Levy9659e592016-10-27 18:08:27 +0300463 memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
464 msg_meta.msg_type = msg_type;
465 msg_meta.msg_len = sizeof(struct ipa_wan_msg);
466 retval = ipa3_send_msg(&msg_meta, wan_msg, ipa3_wan_msg_free_cb);
467 if (retval) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530468 IPAERR_RL("ipa3_send_msg failed: %d\n", retval);
Amir Levy9659e592016-10-27 18:08:27 +0300469 kfree(wan_msg);
470 return retval;
471 }
472
Mohammed Javidb4b5ef42017-08-29 01:05:46 +0530473 if (is_cache) {
474 mutex_lock(&ipa3_ctx->ipa_cne_evt_lock);
475
476 /* cache the cne event */
477 memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[
478 ipa3_ctx->num_ipa_cne_evt_req].wan_msg,
Mohammed Javid616bb992017-10-03 13:10:05 +0530479 &cache_wan_msg,
480 sizeof(cache_wan_msg));
Mohammed Javidb4b5ef42017-08-29 01:05:46 +0530481
482 memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[
483 ipa3_ctx->num_ipa_cne_evt_req].msg_meta,
484 &msg_meta,
485 sizeof(struct ipa_msg_meta));
486
487 ipa3_ctx->num_ipa_cne_evt_req++;
488 ipa3_ctx->num_ipa_cne_evt_req %= IPA_MAX_NUM_REQ_CACHE;
489 mutex_unlock(&ipa3_ctx->ipa_cne_evt_lock);
490 }
491
Amir Levy9659e592016-10-27 18:08:27 +0300492 return 0;
493}
494
Shihuan Liuc3174f52017-05-04 15:59:13 -0700495static void ipa3_vlan_l2tp_msg_free_cb(void *buff, u32 len, u32 type)
496{
497 if (!buff) {
498 IPAERR("Null buffer\n");
499 return;
500 }
501
Amir Levy4f8b4832018-06-05 15:48:03 +0300502 switch (type) {
503 case ADD_VLAN_IFACE:
504 case DEL_VLAN_IFACE:
505 case ADD_L2TP_VLAN_MAPPING:
506 case DEL_L2TP_VLAN_MAPPING:
507 case ADD_BRIDGE_VLAN_MAPPING:
508 case DEL_BRIDGE_VLAN_MAPPING:
509 break;
510 default:
Shihuan Liuc3174f52017-05-04 15:59:13 -0700511 IPAERR("Wrong type given. buff %pK type %d\n", buff, type);
512 return;
513 }
514
515 kfree(buff);
516}
517
518static int ipa3_send_vlan_l2tp_msg(unsigned long usr_param, uint8_t msg_type)
519{
520 int retval;
521 struct ipa_ioc_vlan_iface_info *vlan_info;
522 struct ipa_ioc_l2tp_vlan_mapping_info *mapping_info;
Amir Levy4f8b4832018-06-05 15:48:03 +0300523 struct ipa_ioc_bridge_vlan_mapping_info *bridge_vlan_info;
Shihuan Liuc3174f52017-05-04 15:59:13 -0700524 struct ipa_msg_meta msg_meta;
Amir Levy4f8b4832018-06-05 15:48:03 +0300525 void *buff;
Shihuan Liuc3174f52017-05-04 15:59:13 -0700526
Amir Levy4f8b4832018-06-05 15:48:03 +0300527 IPADBG("type %d\n", msg_type);
528
529 memset(&msg_meta, 0, sizeof(msg_meta));
530 msg_meta.msg_type = msg_type;
531
532 if ((msg_type == ADD_VLAN_IFACE) ||
533 (msg_type == DEL_VLAN_IFACE)) {
Shihuan Liuc3174f52017-05-04 15:59:13 -0700534 vlan_info = kzalloc(sizeof(struct ipa_ioc_vlan_iface_info),
535 GFP_KERNEL);
536 if (!vlan_info) {
537 IPAERR("no memory\n");
538 return -ENOMEM;
539 }
540
541 if (copy_from_user((u8 *)vlan_info, (void __user *)usr_param,
542 sizeof(struct ipa_ioc_vlan_iface_info))) {
543 kfree(vlan_info);
544 return -EFAULT;
545 }
546
Shihuan Liuc3174f52017-05-04 15:59:13 -0700547 msg_meta.msg_len = sizeof(struct ipa_ioc_vlan_iface_info);
Amir Levy4f8b4832018-06-05 15:48:03 +0300548 buff = vlan_info;
549 } else if ((msg_type == ADD_L2TP_VLAN_MAPPING) ||
550 (msg_type == DEL_L2TP_VLAN_MAPPING)) {
Shihuan Liuc3174f52017-05-04 15:59:13 -0700551 mapping_info = kzalloc(sizeof(struct
552 ipa_ioc_l2tp_vlan_mapping_info), GFP_KERNEL);
553 if (!mapping_info) {
554 IPAERR("no memory\n");
555 return -ENOMEM;
556 }
557
558 if (copy_from_user((u8 *)mapping_info,
559 (void __user *)usr_param,
560 sizeof(struct ipa_ioc_l2tp_vlan_mapping_info))) {
561 kfree(mapping_info);
562 return -EFAULT;
563 }
564
Shihuan Liuc3174f52017-05-04 15:59:13 -0700565 msg_meta.msg_len = sizeof(struct
566 ipa_ioc_l2tp_vlan_mapping_info);
Amir Levy4f8b4832018-06-05 15:48:03 +0300567 buff = mapping_info;
568 } else if ((msg_type == ADD_BRIDGE_VLAN_MAPPING) ||
569 (msg_type == DEL_BRIDGE_VLAN_MAPPING)) {
570 bridge_vlan_info = kzalloc(
571 sizeof(struct ipa_ioc_bridge_vlan_mapping_info),
572 GFP_KERNEL);
573 if (!bridge_vlan_info) {
574 IPAERR("no memory\n");
575 return -ENOMEM;
Shihuan Liuc3174f52017-05-04 15:59:13 -0700576 }
Amir Levy4f8b4832018-06-05 15:48:03 +0300577
578 if (copy_from_user((u8 *)bridge_vlan_info,
579 (void __user *)usr_param,
580 sizeof(struct ipa_ioc_bridge_vlan_mapping_info))) {
581 kfree(bridge_vlan_info);
582 IPAERR("copy from user failed\n");
583 return -EFAULT;
584 }
585
586 msg_meta.msg_len = sizeof(struct
587 ipa_ioc_bridge_vlan_mapping_info);
588 buff = bridge_vlan_info;
Shihuan Liuc3174f52017-05-04 15:59:13 -0700589 } else {
590 IPAERR("Unexpected event\n");
591 return -EFAULT;
592 }
593
Amir Levy4f8b4832018-06-05 15:48:03 +0300594 retval = ipa3_send_msg(&msg_meta, buff,
595 ipa3_vlan_l2tp_msg_free_cb);
596 if (retval) {
597 IPAERR("ipa3_send_msg failed: %d, msg_type %d\n",
598 retval,
599 msg_type);
600 kfree(buff);
601 return retval;
602 }
603 IPADBG("exit\n");
604
Shihuan Liuc3174f52017-05-04 15:59:13 -0700605 return 0;
606}
Amir Levy9659e592016-10-27 18:08:27 +0300607
Mohammed Javida0f23d92018-09-11 10:50:28 +0530608static void ipa3_gsb_msg_free_cb(void *buff, u32 len, u32 type)
609{
610 if (!buff) {
611 IPAERR("Null buffer\n");
612 return;
613 }
614
615 switch (type) {
616 case IPA_GSB_CONNECT:
617 case IPA_GSB_DISCONNECT:
618 break;
619 default:
620 IPAERR("Wrong type given. buff %pK type %d\n", buff, type);
621 return;
622 }
623
624 kfree(buff);
625}
626
Mohammed Javidd636e0c2019-06-13 16:16:59 +0530627static void ipa3_get_usb_ep_info(
628 struct ipa_ioc_get_ep_info *ep_info,
629 struct ipa_ep_pair_info *pair_info
630 )
631{
632 int ep_index = -1, i;
633
634 ep_info->num_ep_pairs = 0;
635 for (i = 0; i < ep_info->max_ep_pairs; i++) {
636 pair_info[i].consumer_pipe_num = -1;
637 pair_info[i].producer_pipe_num = -1;
638 pair_info[i].ep_id = -1;
639 }
640
641 ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD);
642
643 if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
644 pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
645 ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB_CONS);
646 if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
647 pair_info[ep_info->num_ep_pairs].producer_pipe_num =
648 ep_index;
649 pair_info[ep_info->num_ep_pairs].ep_id =
650 IPA_USB0_EP_ID;
651
652 IPADBG("ep_pair_info consumer_pipe_num %d",
653 pair_info[ep_info->num_ep_pairs].
654 consumer_pipe_num);
655 IPADBG(" producer_pipe_num %d ep_id %d\n",
656 pair_info[ep_info->num_ep_pairs].
657 producer_pipe_num,
658 pair_info[ep_info->num_ep_pairs].ep_id);
659 ep_info->num_ep_pairs++;
660 } else {
661 pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
662 IPADBG("ep_pair_info consumer_pipe_num %d",
663 pair_info[ep_info->num_ep_pairs].
664 consumer_pipe_num);
665 IPADBG(" producer_pipe_num %d ep_id %d\n",
666 pair_info[ep_info->num_ep_pairs].
667 producer_pipe_num,
668 pair_info[ep_info->num_ep_pairs].ep_id);
669 }
670 }
671
672 ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB2_PROD);
673
674 if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
675 pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
676 ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB2_CONS);
677 if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
678 pair_info[ep_info->num_ep_pairs].producer_pipe_num =
679 ep_index;
680 pair_info[ep_info->num_ep_pairs].ep_id =
681 IPA_USB1_EP_ID;
682
683 IPADBG("ep_pair_info consumer_pipe_num %d",
684 pair_info[ep_info->num_ep_pairs].
685 consumer_pipe_num);
686 IPADBG(" producer_pipe_num %d ep_id %d\n",
687 pair_info[ep_info->num_ep_pairs].
688 producer_pipe_num,
689 pair_info[ep_info->num_ep_pairs].ep_id);
690 ep_info->num_ep_pairs++;
691 } else {
692 pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
693 IPADBG("ep_pair_info consumer_pipe_num %d",
694 pair_info[ep_info->num_ep_pairs].
695 consumer_pipe_num);
696 IPADBG(" producer_pipe_num %d ep_id %d\n",
697 pair_info[ep_info->num_ep_pairs].
698 producer_pipe_num,
699 pair_info[ep_info->num_ep_pairs].ep_id);
700 }
701 }
702}
703
704static void ipa3_get_pcie_ep_info(
705 struct ipa_ioc_get_ep_info *ep_info,
706 struct ipa_ep_pair_info *pair_info
707 )
708{
709 int ep_index = -1, i;
710
711 ep_info->num_ep_pairs = 0;
712 for (i = 0; i < ep_info->max_ep_pairs; i++) {
713 pair_info[i].consumer_pipe_num = -1;
714 pair_info[i].producer_pipe_num = -1;
715 pair_info[i].ep_id = -1;
716 }
717
718 ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI_PROD);
719
720 if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
721 pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
722 ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI_CONS);
723 if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
724 pair_info[ep_info->num_ep_pairs].producer_pipe_num =
725 ep_index;
726 pair_info[ep_info->num_ep_pairs].ep_id =
727 IPA_PCIE0_EP_ID;
728
729 IPADBG("ep_pair_info consumer_pipe_num %d",
730 pair_info[ep_info->num_ep_pairs].
731 consumer_pipe_num);
732 IPADBG(" producer_pipe_num %d ep_id %d\n",
733 pair_info[ep_info->num_ep_pairs].
734 producer_pipe_num,
735 pair_info[ep_info->num_ep_pairs].ep_id);
736 ep_info->num_ep_pairs++;
737 } else {
738 pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
739 IPADBG("ep_pair_info consumer_pipe_num %d",
740 pair_info[ep_info->num_ep_pairs].
741 consumer_pipe_num);
742 IPADBG(" producer_pipe_num %d ep_id %d\n",
743 pair_info[ep_info->num_ep_pairs].
744 producer_pipe_num,
745 pair_info[ep_info->num_ep_pairs].ep_id);
746 }
747 }
748
749 ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI2_PROD);
750
751 if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
752 pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
753 ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI2_CONS);
754 if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
755 pair_info[ep_info->num_ep_pairs].producer_pipe_num =
756 ep_index;
757 pair_info[ep_info->num_ep_pairs].ep_id =
758 IPA_PCIE1_EP_ID;
759
760 IPADBG("ep_pair_info consumer_pipe_num %d",
761 pair_info[ep_info->num_ep_pairs].
762 consumer_pipe_num);
763 IPADBG(" producer_pipe_num %d ep_id %d\n",
764 pair_info[ep_info->num_ep_pairs].
765 producer_pipe_num,
766 pair_info[ep_info->num_ep_pairs].ep_id);
767 ep_info->num_ep_pairs++;
768 } else {
769 pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
770 IPADBG("ep_pair_info consumer_pipe_num %d",
771 pair_info[ep_info->num_ep_pairs].
772 consumer_pipe_num);
773 IPADBG(" producer_pipe_num %d ep_id %d\n",
774 pair_info[ep_info->num_ep_pairs].
775 producer_pipe_num,
776 pair_info[ep_info->num_ep_pairs].ep_id);
777 }
778 }
779}
780
781
782static int ipa3_get_ep_info(struct ipa_ioc_get_ep_info *ep_info,
783 u8 *param)
784{
785 int ret = 0;
786 struct ipa_ep_pair_info *pair_info = (struct ipa_ep_pair_info *)param;
787
788 switch (ep_info->ep_type) {
789 case IPA_DATA_EP_TYP_HSUSB:
790 ipa3_get_usb_ep_info(ep_info, pair_info);
791 break;
792
793 case IPA_DATA_EP_TYP_PCIE:
794 ipa3_get_pcie_ep_info(ep_info, pair_info);
795 break;
796
797 default:
798 IPAERR_RL("Undefined ep_type %d\n", ep_info->ep_type);
799 ret = -EFAULT;
800 break;
801 }
802
803 return ret;
804}
805
Mohammed Javida0f23d92018-09-11 10:50:28 +0530806static int ipa3_send_gsb_msg(unsigned long usr_param, uint8_t msg_type)
807{
808 int retval;
809 struct ipa_ioc_gsb_info *gsb_info;
810 struct ipa_msg_meta msg_meta;
811 void *buff;
812
813 IPADBG("type %d\n", msg_type);
814
815 memset(&msg_meta, 0, sizeof(msg_meta));
816 msg_meta.msg_type = msg_type;
817
818 if ((msg_type == IPA_GSB_CONNECT) ||
819 (msg_type == IPA_GSB_DISCONNECT)) {
820 gsb_info = kzalloc(sizeof(struct ipa_ioc_gsb_info),
821 GFP_KERNEL);
822 if (!gsb_info) {
823 IPAERR("no memory\n");
824 return -ENOMEM;
825 }
826
827 if (copy_from_user((u8 *)gsb_info, (void __user *)usr_param,
828 sizeof(struct ipa_ioc_gsb_info))) {
829 kfree(gsb_info);
830 return -EFAULT;
831 }
832
833 msg_meta.msg_len = sizeof(struct ipa_ioc_gsb_info);
834 buff = gsb_info;
835 } else {
836 IPAERR("Unexpected event\n");
837 return -EFAULT;
838 }
839
840 retval = ipa3_send_msg(&msg_meta, buff,
841 ipa3_gsb_msg_free_cb);
842 if (retval) {
843 IPAERR("ipa3_send_msg failed: %d, msg_type %d\n",
844 retval,
845 msg_type);
846 kfree(buff);
847 return retval;
848 }
849 IPADBG("exit\n");
850
851 return 0;
852}
853
Amir Levy9659e592016-10-27 18:08:27 +0300854static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
855{
856 int retval = 0;
857 u32 pyld_sz;
858 u8 header[128] = { 0 };
859 u8 *param = NULL;
Amir Levya5361ab2018-05-01 13:25:37 +0300860 bool is_vlan_mode;
Amir Levy9659e592016-10-27 18:08:27 +0300861 struct ipa_ioc_nat_alloc_mem nat_mem;
Amir Levy479cfdd2017-10-26 12:23:14 +0300862 struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc;
Amir Levy9659e592016-10-27 18:08:27 +0300863 struct ipa_ioc_v4_nat_init nat_init;
Amir Levy479cfdd2017-10-26 12:23:14 +0300864 struct ipa_ioc_ipv6ct_init ipv6ct_init;
Amir Levy9659e592016-10-27 18:08:27 +0300865 struct ipa_ioc_v4_nat_del nat_del;
Amir Levy479cfdd2017-10-26 12:23:14 +0300866 struct ipa_ioc_nat_ipv6ct_table_del table_del;
Amir Levy05fccd02017-06-13 16:25:45 +0300867 struct ipa_ioc_nat_pdn_entry mdfy_pdn;
Amir Levy9659e592016-10-27 18:08:27 +0300868 struct ipa_ioc_rm_dependency rm_depend;
Amir Levy479cfdd2017-10-26 12:23:14 +0300869 struct ipa_ioc_nat_dma_cmd *table_dma_cmd;
Amir Levya5361ab2018-05-01 13:25:37 +0300870 struct ipa_ioc_get_vlan_mode vlan_mode;
Mohammed Javidd636e0c2019-06-13 16:16:59 +0530871 struct ipa_ioc_get_ep_info ep_info;
Amir Levy9659e592016-10-27 18:08:27 +0300872 size_t sz;
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200873 int pre_entry;
Mohammed Javidd636e0c2019-06-13 16:16:59 +0530874 unsigned long uptr = 0;
Amir Levy9659e592016-10-27 18:08:27 +0300875
876 IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
877
Amir Levy9659e592016-10-27 18:08:27 +0300878 if (_IOC_TYPE(cmd) != IPA_IOC_MAGIC)
879 return -ENOTTY;
Amir Levy9659e592016-10-27 18:08:27 +0300880
Amir Levy05532622016-11-28 12:12:01 +0200881 if (!ipa3_is_ready()) {
882 IPAERR("IPA not ready, waiting for init completion\n");
883 wait_for_completion(&ipa3_ctx->init_completion_obj);
884 }
885
Amir Levy9659e592016-10-27 18:08:27 +0300886 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
887
888 switch (cmd) {
889 case IPA_IOC_ALLOC_NAT_MEM:
Amir Levy479cfdd2017-10-26 12:23:14 +0300890 if (copy_from_user(&nat_mem, (const void __user *)arg,
891 sizeof(struct ipa_ioc_nat_alloc_mem))) {
Amir Levy9659e592016-10-27 18:08:27 +0300892 retval = -EFAULT;
893 break;
894 }
895 /* null terminate the string */
896 nat_mem.dev_name[IPA_RESOURCE_NAME_MAX - 1] = '\0';
897
898 if (ipa3_allocate_nat_device(&nat_mem)) {
899 retval = -EFAULT;
900 break;
901 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300902 if (copy_to_user((void __user *)arg, &nat_mem,
903 sizeof(struct ipa_ioc_nat_alloc_mem))) {
Amir Levy9659e592016-10-27 18:08:27 +0300904 retval = -EFAULT;
905 break;
906 }
907 break;
Amir Levy479cfdd2017-10-26 12:23:14 +0300908 case IPA_IOC_ALLOC_NAT_TABLE:
909 if (copy_from_user(&table_alloc, (const void __user *)arg,
910 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc))) {
911 retval = -EFAULT;
912 break;
913 }
914
915 if (ipa3_allocate_nat_table(&table_alloc)) {
916 retval = -EFAULT;
917 break;
918 }
919 if (table_alloc.offset &&
920 copy_to_user((void __user *)arg, &table_alloc, sizeof(
921 struct ipa_ioc_nat_ipv6ct_table_alloc))) {
922 retval = -EFAULT;
923 break;
924 }
925 break;
926
927 case IPA_IOC_ALLOC_IPV6CT_TABLE:
928 if (copy_from_user(&table_alloc, (const void __user *)arg,
929 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc))) {
930 retval = -EFAULT;
931 break;
932 }
933
934 if (ipa3_allocate_ipv6ct_table(&table_alloc)) {
935 retval = -EFAULT;
936 break;
937 }
938 if (table_alloc.offset &&
939 copy_to_user((void __user *)arg, &table_alloc, sizeof(
940 struct ipa_ioc_nat_ipv6ct_table_alloc))) {
941 retval = -EFAULT;
942 break;
943 }
944 break;
945
Amir Levy9659e592016-10-27 18:08:27 +0300946 case IPA_IOC_V4_INIT_NAT:
Amir Levy479cfdd2017-10-26 12:23:14 +0300947 if (copy_from_user(&nat_init, (const void __user *)arg,
948 sizeof(struct ipa_ioc_v4_nat_init))) {
Amir Levy9659e592016-10-27 18:08:27 +0300949 retval = -EFAULT;
950 break;
951 }
952 if (ipa3_nat_init_cmd(&nat_init)) {
953 retval = -EFAULT;
954 break;
955 }
956 break;
957
Amir Levy479cfdd2017-10-26 12:23:14 +0300958 case IPA_IOC_INIT_IPV6CT_TABLE:
959 if (copy_from_user(&ipv6ct_init, (const void __user *)arg,
960 sizeof(struct ipa_ioc_ipv6ct_init))) {
Amir Levy9659e592016-10-27 18:08:27 +0300961 retval = -EFAULT;
962 break;
963 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300964 if (ipa3_ipv6ct_init_cmd(&ipv6ct_init)) {
965 retval = -EFAULT;
966 break;
967 }
968 break;
969
970 case IPA_IOC_TABLE_DMA_CMD:
971 table_dma_cmd = (struct ipa_ioc_nat_dma_cmd *)header;
972 if (copy_from_user(header, (const void __user *)arg,
973 sizeof(struct ipa_ioc_nat_dma_cmd))) {
974 retval = -EFAULT;
975 break;
976 }
977 pre_entry = table_dma_cmd->entries;
978 pyld_sz = sizeof(struct ipa_ioc_nat_dma_cmd) +
979 pre_entry * sizeof(struct ipa_ioc_nat_dma_one);
Amir Levy9659e592016-10-27 18:08:27 +0300980 param = kzalloc(pyld_sz, GFP_KERNEL);
981 if (!param) {
982 retval = -ENOMEM;
983 break;
984 }
985
Amir Levy479cfdd2017-10-26 12:23:14 +0300986 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300987 retval = -EFAULT;
988 break;
989 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300990 table_dma_cmd = (struct ipa_ioc_nat_dma_cmd *)param;
991
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200992 /* add check in case user-space module compromised */
Amir Levy479cfdd2017-10-26 12:23:14 +0300993 if (unlikely(table_dma_cmd->entries != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530994 IPAERR_RL("current %d pre %d\n",
Amir Levy479cfdd2017-10-26 12:23:14 +0300995 table_dma_cmd->entries, pre_entry);
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200996 retval = -EFAULT;
997 break;
998 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300999 if (ipa3_table_dma_cmd(table_dma_cmd)) {
Amir Levy9659e592016-10-27 18:08:27 +03001000 retval = -EFAULT;
1001 break;
1002 }
1003 break;
1004
1005 case IPA_IOC_V4_DEL_NAT:
Amir Levy479cfdd2017-10-26 12:23:14 +03001006 if (copy_from_user(&nat_del, (const void __user *)arg,
1007 sizeof(struct ipa_ioc_v4_nat_del))) {
Amir Levy9659e592016-10-27 18:08:27 +03001008 retval = -EFAULT;
1009 break;
1010 }
1011 if (ipa3_nat_del_cmd(&nat_del)) {
1012 retval = -EFAULT;
1013 break;
1014 }
1015 break;
1016
Amir Levy479cfdd2017-10-26 12:23:14 +03001017 case IPA_IOC_DEL_NAT_TABLE:
1018 if (copy_from_user(&table_del, (const void __user *)arg,
1019 sizeof(struct ipa_ioc_nat_ipv6ct_table_del))) {
1020 retval = -EFAULT;
1021 break;
1022 }
1023 if (ipa3_del_nat_table(&table_del)) {
1024 retval = -EFAULT;
1025 break;
1026 }
1027 break;
1028
1029 case IPA_IOC_DEL_IPV6CT_TABLE:
1030 if (copy_from_user(&table_del, (const void __user *)arg,
1031 sizeof(struct ipa_ioc_nat_ipv6ct_table_del))) {
1032 retval = -EFAULT;
1033 break;
1034 }
1035 if (ipa3_del_ipv6ct_table(&table_del)) {
1036 retval = -EFAULT;
1037 break;
1038 }
1039 break;
1040
Amir Levy05fccd02017-06-13 16:25:45 +03001041 case IPA_IOC_NAT_MODIFY_PDN:
Amir Levy479cfdd2017-10-26 12:23:14 +03001042 if (copy_from_user(&mdfy_pdn, (const void __user *)arg,
Amir Levy05fccd02017-06-13 16:25:45 +03001043 sizeof(struct ipa_ioc_nat_pdn_entry))) {
1044 retval = -EFAULT;
1045 break;
1046 }
Amir Levydc65f4c2017-07-06 09:49:50 +03001047 if (ipa3_nat_mdfy_pdn(&mdfy_pdn)) {
Amir Levy05fccd02017-06-13 16:25:45 +03001048 retval = -EFAULT;
1049 break;
1050 }
1051 break;
1052
Amir Levy9659e592016-10-27 18:08:27 +03001053 case IPA_IOC_ADD_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +03001054 if (copy_from_user(header, (const void __user *)arg,
1055 sizeof(struct ipa_ioc_add_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001056 retval = -EFAULT;
1057 break;
1058 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001059 pre_entry =
1060 ((struct ipa_ioc_add_hdr *)header)->num_hdrs;
Amir Levy9659e592016-10-27 18:08:27 +03001061 pyld_sz =
1062 sizeof(struct ipa_ioc_add_hdr) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001063 pre_entry * sizeof(struct ipa_hdr_add);
Amir Levy9659e592016-10-27 18:08:27 +03001064 param = kzalloc(pyld_sz, GFP_KERNEL);
1065 if (!param) {
1066 retval = -ENOMEM;
1067 break;
1068 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001069 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001070 retval = -EFAULT;
1071 break;
1072 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001073 /* add check in case user-space module compromised */
1074 if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs
1075 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301076 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001077 ((struct ipa_ioc_add_hdr *)param)->num_hdrs,
1078 pre_entry);
1079 retval = -EFAULT;
1080 break;
1081 }
Skylar Chang68c37d82018-04-07 16:42:36 -07001082 if (ipa3_add_hdr_usr((struct ipa_ioc_add_hdr *)param,
1083 true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001084 retval = -EFAULT;
1085 break;
1086 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001087 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001088 retval = -EFAULT;
1089 break;
1090 }
1091 break;
1092
1093 case IPA_IOC_DEL_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +03001094 if (copy_from_user(header, (const void __user *)arg,
1095 sizeof(struct ipa_ioc_del_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001096 retval = -EFAULT;
1097 break;
1098 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001099 pre_entry =
1100 ((struct ipa_ioc_del_hdr *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001101 pyld_sz =
1102 sizeof(struct ipa_ioc_del_hdr) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001103 pre_entry * sizeof(struct ipa_hdr_del);
Amir Levy9659e592016-10-27 18:08:27 +03001104 param = kzalloc(pyld_sz, GFP_KERNEL);
1105 if (!param) {
1106 retval = -ENOMEM;
1107 break;
1108 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001109 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001110 retval = -EFAULT;
1111 break;
1112 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001113 /* add check in case user-space module compromised */
1114 if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls
1115 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301116 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001117 ((struct ipa_ioc_del_hdr *)param)->num_hdls,
1118 pre_entry);
1119 retval = -EFAULT;
1120 break;
1121 }
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02001122 if (ipa3_del_hdr_by_user((struct ipa_ioc_del_hdr *)param,
1123 true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001124 retval = -EFAULT;
1125 break;
1126 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001127 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001128 retval = -EFAULT;
1129 break;
1130 }
1131 break;
1132
1133 case IPA_IOC_ADD_RT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001134 if (copy_from_user(header, (const void __user *)arg,
1135 sizeof(struct ipa_ioc_add_rt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001136 retval = -EFAULT;
1137 break;
1138 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001139 pre_entry =
1140 ((struct ipa_ioc_add_rt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001141 pyld_sz =
1142 sizeof(struct ipa_ioc_add_rt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001143 pre_entry * sizeof(struct ipa_rt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001144 param = kzalloc(pyld_sz, GFP_KERNEL);
1145 if (!param) {
1146 retval = -ENOMEM;
1147 break;
1148 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001149 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001150 retval = -EFAULT;
1151 break;
1152 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001153 /* add check in case user-space module compromised */
1154 if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules
1155 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301156 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001157 ((struct ipa_ioc_add_rt_rule *)param)->
1158 num_rules,
1159 pre_entry);
1160 retval = -EFAULT;
1161 break;
1162 }
Skylar Chang68c37d82018-04-07 16:42:36 -07001163 if (ipa3_add_rt_rule_usr((struct ipa_ioc_add_rt_rule *)param,
1164 true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001165 retval = -EFAULT;
1166 break;
1167 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001168 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001169 retval = -EFAULT;
1170 break;
1171 }
1172 break;
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05301173
1174 case IPA_IOC_ADD_RT_RULE_EXT:
1175 if (copy_from_user(header,
1176 (const void __user *)arg,
1177 sizeof(struct ipa_ioc_add_rt_rule_ext))) {
1178 retval = -EFAULT;
1179 break;
1180 }
1181 pre_entry =
1182 ((struct ipa_ioc_add_rt_rule_ext *)header)->num_rules;
1183 pyld_sz =
1184 sizeof(struct ipa_ioc_add_rt_rule_ext) +
1185 pre_entry * sizeof(struct ipa_rt_rule_add_ext);
1186 param = kzalloc(pyld_sz, GFP_KERNEL);
1187 if (!param) {
1188 retval = -ENOMEM;
1189 break;
1190 }
1191 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
1192 retval = -EFAULT;
1193 break;
1194 }
1195 /* add check in case user-space module compromised */
1196 if (unlikely(
1197 ((struct ipa_ioc_add_rt_rule_ext *)param)->num_rules
1198 != pre_entry)) {
1199 IPAERR(" prevent memory corruption(%d not match %d)\n",
1200 ((struct ipa_ioc_add_rt_rule_ext *)param)->
1201 num_rules,
1202 pre_entry);
1203 retval = -EINVAL;
1204 break;
1205 }
1206 if (ipa3_add_rt_rule_ext(
1207 (struct ipa_ioc_add_rt_rule_ext *)param)) {
1208 retval = -EFAULT;
1209 break;
1210 }
1211 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
1212 retval = -EFAULT;
1213 break;
1214 }
1215 break;
Amir Levy9659e592016-10-27 18:08:27 +03001216 case IPA_IOC_ADD_RT_RULE_AFTER:
Amir Levy479cfdd2017-10-26 12:23:14 +03001217 if (copy_from_user(header, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001218 sizeof(struct ipa_ioc_add_rt_rule_after))) {
1219
1220 retval = -EFAULT;
1221 break;
1222 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001223 pre_entry =
1224 ((struct ipa_ioc_add_rt_rule_after *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001225 pyld_sz =
1226 sizeof(struct ipa_ioc_add_rt_rule_after) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001227 pre_entry * sizeof(struct ipa_rt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001228 param = kzalloc(pyld_sz, GFP_KERNEL);
1229 if (!param) {
1230 retval = -ENOMEM;
1231 break;
1232 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001233 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001234 retval = -EFAULT;
1235 break;
1236 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001237 /* add check in case user-space module compromised */
1238 if (unlikely(((struct ipa_ioc_add_rt_rule_after *)param)->
1239 num_rules != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301240 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001241 ((struct ipa_ioc_add_rt_rule_after *)param)->
1242 num_rules,
1243 pre_entry);
1244 retval = -EFAULT;
1245 break;
1246 }
Amir Levy9659e592016-10-27 18:08:27 +03001247 if (ipa3_add_rt_rule_after(
1248 (struct ipa_ioc_add_rt_rule_after *)param)) {
1249
1250 retval = -EFAULT;
1251 break;
1252 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001253 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001254 retval = -EFAULT;
1255 break;
1256 }
1257 break;
1258
1259 case IPA_IOC_MDFY_RT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001260 if (copy_from_user(header, (const void __user *)arg,
1261 sizeof(struct ipa_ioc_mdfy_rt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001262 retval = -EFAULT;
1263 break;
1264 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001265 pre_entry =
1266 ((struct ipa_ioc_mdfy_rt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001267 pyld_sz =
1268 sizeof(struct ipa_ioc_mdfy_rt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001269 pre_entry * sizeof(struct ipa_rt_rule_mdfy);
Amir Levy9659e592016-10-27 18:08:27 +03001270 param = kzalloc(pyld_sz, GFP_KERNEL);
1271 if (!param) {
1272 retval = -ENOMEM;
1273 break;
1274 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001275 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001276 retval = -EFAULT;
1277 break;
1278 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001279 /* add check in case user-space module compromised */
1280 if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules
1281 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301282 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001283 ((struct ipa_ioc_mdfy_rt_rule *)param)->
1284 num_rules,
1285 pre_entry);
1286 retval = -EFAULT;
1287 break;
1288 }
Amir Levy9659e592016-10-27 18:08:27 +03001289 if (ipa3_mdfy_rt_rule((struct ipa_ioc_mdfy_rt_rule *)param)) {
1290 retval = -EFAULT;
1291 break;
1292 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001293 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001294 retval = -EFAULT;
1295 break;
1296 }
1297 break;
1298
1299 case IPA_IOC_DEL_RT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001300 if (copy_from_user(header, (const void __user *)arg,
1301 sizeof(struct ipa_ioc_del_rt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001302 retval = -EFAULT;
1303 break;
1304 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001305 pre_entry =
1306 ((struct ipa_ioc_del_rt_rule *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001307 pyld_sz =
1308 sizeof(struct ipa_ioc_del_rt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001309 pre_entry * sizeof(struct ipa_rt_rule_del);
Amir Levy9659e592016-10-27 18:08:27 +03001310 param = kzalloc(pyld_sz, GFP_KERNEL);
1311 if (!param) {
1312 retval = -ENOMEM;
1313 break;
1314 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001315 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001316 retval = -EFAULT;
1317 break;
1318 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001319 /* add check in case user-space module compromised */
1320 if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls
1321 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301322 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001323 ((struct ipa_ioc_del_rt_rule *)param)->num_hdls,
1324 pre_entry);
1325 retval = -EFAULT;
1326 break;
1327 }
Amir Levy9659e592016-10-27 18:08:27 +03001328 if (ipa3_del_rt_rule((struct ipa_ioc_del_rt_rule *)param)) {
1329 retval = -EFAULT;
1330 break;
1331 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001332 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001333 retval = -EFAULT;
1334 break;
1335 }
1336 break;
1337
1338 case IPA_IOC_ADD_FLT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001339 if (copy_from_user(header, (const void __user *)arg,
1340 sizeof(struct ipa_ioc_add_flt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001341 retval = -EFAULT;
1342 break;
1343 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001344 pre_entry =
1345 ((struct ipa_ioc_add_flt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001346 pyld_sz =
1347 sizeof(struct ipa_ioc_add_flt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001348 pre_entry * sizeof(struct ipa_flt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001349 param = kzalloc(pyld_sz, GFP_KERNEL);
1350 if (!param) {
1351 retval = -ENOMEM;
1352 break;
1353 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001354 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001355 retval = -EFAULT;
1356 break;
1357 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001358 /* add check in case user-space module compromised */
1359 if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules
1360 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301361 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001362 ((struct ipa_ioc_add_flt_rule *)param)->
1363 num_rules,
1364 pre_entry);
1365 retval = -EFAULT;
1366 break;
1367 }
Skylar Chang68c37d82018-04-07 16:42:36 -07001368 if (ipa3_add_flt_rule_usr((struct ipa_ioc_add_flt_rule *)param,
1369 true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001370 retval = -EFAULT;
1371 break;
1372 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001373 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001374 retval = -EFAULT;
1375 break;
1376 }
1377 break;
1378
1379 case IPA_IOC_ADD_FLT_RULE_AFTER:
Amir Levy479cfdd2017-10-26 12:23:14 +03001380 if (copy_from_user(header, (const void __user *)arg,
1381 sizeof(struct ipa_ioc_add_flt_rule_after))) {
Amir Levy9659e592016-10-27 18:08:27 +03001382
1383 retval = -EFAULT;
1384 break;
1385 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001386 pre_entry =
1387 ((struct ipa_ioc_add_flt_rule_after *)header)->
1388 num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001389 pyld_sz =
1390 sizeof(struct ipa_ioc_add_flt_rule_after) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001391 pre_entry * sizeof(struct ipa_flt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001392 param = kzalloc(pyld_sz, GFP_KERNEL);
1393 if (!param) {
1394 retval = -ENOMEM;
1395 break;
1396 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001397 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001398 retval = -EFAULT;
1399 break;
1400 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001401 /* add check in case user-space module compromised */
1402 if (unlikely(((struct ipa_ioc_add_flt_rule_after *)param)->
1403 num_rules != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301404 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001405 ((struct ipa_ioc_add_flt_rule_after *)param)->
1406 num_rules,
1407 pre_entry);
1408 retval = -EFAULT;
1409 break;
1410 }
Amir Levy9659e592016-10-27 18:08:27 +03001411 if (ipa3_add_flt_rule_after(
1412 (struct ipa_ioc_add_flt_rule_after *)param)) {
1413 retval = -EFAULT;
1414 break;
1415 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001416 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001417 retval = -EFAULT;
1418 break;
1419 }
1420 break;
1421
1422 case IPA_IOC_DEL_FLT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001423 if (copy_from_user(header, (const void __user *)arg,
1424 sizeof(struct ipa_ioc_del_flt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001425 retval = -EFAULT;
1426 break;
1427 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001428 pre_entry =
1429 ((struct ipa_ioc_del_flt_rule *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001430 pyld_sz =
1431 sizeof(struct ipa_ioc_del_flt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001432 pre_entry * sizeof(struct ipa_flt_rule_del);
Amir Levy9659e592016-10-27 18:08:27 +03001433 param = kzalloc(pyld_sz, GFP_KERNEL);
1434 if (!param) {
1435 retval = -ENOMEM;
1436 break;
1437 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001438 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001439 retval = -EFAULT;
1440 break;
1441 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001442 /* add check in case user-space module compromised */
1443 if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls
1444 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301445 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001446 ((struct ipa_ioc_del_flt_rule *)param)->
1447 num_hdls,
1448 pre_entry);
1449 retval = -EFAULT;
1450 break;
1451 }
Amir Levy9659e592016-10-27 18:08:27 +03001452 if (ipa3_del_flt_rule((struct ipa_ioc_del_flt_rule *)param)) {
1453 retval = -EFAULT;
1454 break;
1455 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001456 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001457 retval = -EFAULT;
1458 break;
1459 }
1460 break;
1461
1462 case IPA_IOC_MDFY_FLT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001463 if (copy_from_user(header, (const void __user *)arg,
1464 sizeof(struct ipa_ioc_mdfy_flt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001465 retval = -EFAULT;
1466 break;
1467 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001468 pre_entry =
1469 ((struct ipa_ioc_mdfy_flt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001470 pyld_sz =
1471 sizeof(struct ipa_ioc_mdfy_flt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001472 pre_entry * sizeof(struct ipa_flt_rule_mdfy);
Amir Levy9659e592016-10-27 18:08:27 +03001473 param = kzalloc(pyld_sz, GFP_KERNEL);
1474 if (!param) {
1475 retval = -ENOMEM;
1476 break;
1477 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001478 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001479 retval = -EFAULT;
1480 break;
1481 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001482 /* add check in case user-space module compromised */
1483 if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules
1484 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301485 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001486 ((struct ipa_ioc_mdfy_flt_rule *)param)->
1487 num_rules,
1488 pre_entry);
1489 retval = -EFAULT;
1490 break;
1491 }
Amir Levy9659e592016-10-27 18:08:27 +03001492 if (ipa3_mdfy_flt_rule((struct ipa_ioc_mdfy_flt_rule *)param)) {
1493 retval = -EFAULT;
1494 break;
1495 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001496 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001497 retval = -EFAULT;
1498 break;
1499 }
1500 break;
1501
1502 case IPA_IOC_COMMIT_HDR:
1503 retval = ipa3_commit_hdr();
1504 break;
1505 case IPA_IOC_RESET_HDR:
Skylar Chang68c37d82018-04-07 16:42:36 -07001506 retval = ipa3_reset_hdr(false);
Amir Levy9659e592016-10-27 18:08:27 +03001507 break;
1508 case IPA_IOC_COMMIT_RT:
1509 retval = ipa3_commit_rt(arg);
1510 break;
1511 case IPA_IOC_RESET_RT:
Skylar Chang68c37d82018-04-07 16:42:36 -07001512 retval = ipa3_reset_rt(arg, false);
Amir Levy9659e592016-10-27 18:08:27 +03001513 break;
1514 case IPA_IOC_COMMIT_FLT:
1515 retval = ipa3_commit_flt(arg);
1516 break;
1517 case IPA_IOC_RESET_FLT:
Skylar Chang68c37d82018-04-07 16:42:36 -07001518 retval = ipa3_reset_flt(arg, false);
Amir Levy9659e592016-10-27 18:08:27 +03001519 break;
1520 case IPA_IOC_GET_RT_TBL:
Amir Levy479cfdd2017-10-26 12:23:14 +03001521 if (copy_from_user(header, (const void __user *)arg,
1522 sizeof(struct ipa_ioc_get_rt_tbl))) {
Amir Levy9659e592016-10-27 18:08:27 +03001523 retval = -EFAULT;
1524 break;
1525 }
1526 if (ipa3_get_rt_tbl((struct ipa_ioc_get_rt_tbl *)header)) {
1527 retval = -EFAULT;
1528 break;
1529 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001530 if (copy_to_user((void __user *)arg, header,
Amir Levy9659e592016-10-27 18:08:27 +03001531 sizeof(struct ipa_ioc_get_rt_tbl))) {
1532 retval = -EFAULT;
1533 break;
1534 }
1535 break;
1536 case IPA_IOC_PUT_RT_TBL:
1537 retval = ipa3_put_rt_tbl(arg);
1538 break;
1539 case IPA_IOC_GET_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +03001540 if (copy_from_user(header, (const void __user *)arg,
1541 sizeof(struct ipa_ioc_get_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001542 retval = -EFAULT;
1543 break;
1544 }
1545 if (ipa3_get_hdr((struct ipa_ioc_get_hdr *)header)) {
1546 retval = -EFAULT;
1547 break;
1548 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001549 if (copy_to_user((void __user *)arg, header,
1550 sizeof(struct ipa_ioc_get_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001551 retval = -EFAULT;
1552 break;
1553 }
1554 break;
1555 case IPA_IOC_PUT_HDR:
1556 retval = ipa3_put_hdr(arg);
1557 break;
1558 case IPA_IOC_SET_FLT:
1559 retval = ipa3_cfg_filter(arg);
1560 break;
1561 case IPA_IOC_COPY_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +03001562 if (copy_from_user(header, (const void __user *)arg,
1563 sizeof(struct ipa_ioc_copy_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001564 retval = -EFAULT;
1565 break;
1566 }
1567 if (ipa3_copy_hdr((struct ipa_ioc_copy_hdr *)header)) {
1568 retval = -EFAULT;
1569 break;
1570 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001571 if (copy_to_user((void __user *)arg, header,
1572 sizeof(struct ipa_ioc_copy_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001573 retval = -EFAULT;
1574 break;
1575 }
1576 break;
1577 case IPA_IOC_QUERY_INTF:
Amir Levy479cfdd2017-10-26 12:23:14 +03001578 if (copy_from_user(header, (const void __user *)arg,
1579 sizeof(struct ipa_ioc_query_intf))) {
Amir Levy9659e592016-10-27 18:08:27 +03001580 retval = -EFAULT;
1581 break;
1582 }
1583 if (ipa3_query_intf((struct ipa_ioc_query_intf *)header)) {
1584 retval = -1;
1585 break;
1586 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001587 if (copy_to_user((void __user *)arg, header,
1588 sizeof(struct ipa_ioc_query_intf))) {
Amir Levy9659e592016-10-27 18:08:27 +03001589 retval = -EFAULT;
1590 break;
1591 }
1592 break;
1593 case IPA_IOC_QUERY_INTF_TX_PROPS:
1594 sz = sizeof(struct ipa_ioc_query_intf_tx_props);
Amir Levy479cfdd2017-10-26 12:23:14 +03001595 if (copy_from_user(header, (const void __user *)arg, sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001596 retval = -EFAULT;
1597 break;
1598 }
1599
1600 if (((struct ipa_ioc_query_intf_tx_props *)header)->num_tx_props
Amir Levy479cfdd2017-10-26 12:23:14 +03001601 > IPA_NUM_PROPS_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001602 retval = -EFAULT;
1603 break;
1604 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001605 pre_entry =
1606 ((struct ipa_ioc_query_intf_tx_props *)
1607 header)->num_tx_props;
1608 pyld_sz = sz + pre_entry *
Amir Levy9659e592016-10-27 18:08:27 +03001609 sizeof(struct ipa_ioc_tx_intf_prop);
1610 param = kzalloc(pyld_sz, GFP_KERNEL);
1611 if (!param) {
1612 retval = -ENOMEM;
1613 break;
1614 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001615 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001616 retval = -EFAULT;
1617 break;
1618 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001619 /* add check in case user-space module compromised */
1620 if (unlikely(((struct ipa_ioc_query_intf_tx_props *)
1621 param)->num_tx_props
1622 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301623 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001624 ((struct ipa_ioc_query_intf_tx_props *)
1625 param)->num_tx_props, pre_entry);
1626 retval = -EFAULT;
1627 break;
1628 }
Amir Levy9659e592016-10-27 18:08:27 +03001629 if (ipa3_query_intf_tx_props(
Amir Levy479cfdd2017-10-26 12:23:14 +03001630 (struct ipa_ioc_query_intf_tx_props *)param)) {
Amir Levy9659e592016-10-27 18:08:27 +03001631 retval = -1;
1632 break;
1633 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001634 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001635 retval = -EFAULT;
1636 break;
1637 }
1638 break;
1639 case IPA_IOC_QUERY_INTF_RX_PROPS:
1640 sz = sizeof(struct ipa_ioc_query_intf_rx_props);
Amir Levy479cfdd2017-10-26 12:23:14 +03001641 if (copy_from_user(header, (const void __user *)arg, sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001642 retval = -EFAULT;
1643 break;
1644 }
1645
1646 if (((struct ipa_ioc_query_intf_rx_props *)header)->num_rx_props
Amir Levy479cfdd2017-10-26 12:23:14 +03001647 > IPA_NUM_PROPS_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001648 retval = -EFAULT;
1649 break;
1650 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001651 pre_entry =
1652 ((struct ipa_ioc_query_intf_rx_props *)
1653 header)->num_rx_props;
1654 pyld_sz = sz + pre_entry *
Amir Levy9659e592016-10-27 18:08:27 +03001655 sizeof(struct ipa_ioc_rx_intf_prop);
1656 param = kzalloc(pyld_sz, GFP_KERNEL);
1657 if (!param) {
1658 retval = -ENOMEM;
1659 break;
1660 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001661 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001662 retval = -EFAULT;
1663 break;
1664 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001665 /* add check in case user-space module compromised */
1666 if (unlikely(((struct ipa_ioc_query_intf_rx_props *)
1667 param)->num_rx_props != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301668 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001669 ((struct ipa_ioc_query_intf_rx_props *)
1670 param)->num_rx_props, pre_entry);
1671 retval = -EFAULT;
1672 break;
1673 }
Amir Levy9659e592016-10-27 18:08:27 +03001674 if (ipa3_query_intf_rx_props(
Amir Levy479cfdd2017-10-26 12:23:14 +03001675 (struct ipa_ioc_query_intf_rx_props *)param)) {
Amir Levy9659e592016-10-27 18:08:27 +03001676 retval = -1;
1677 break;
1678 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001679 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001680 retval = -EFAULT;
1681 break;
1682 }
1683 break;
1684 case IPA_IOC_QUERY_INTF_EXT_PROPS:
1685 sz = sizeof(struct ipa_ioc_query_intf_ext_props);
Amir Levy479cfdd2017-10-26 12:23:14 +03001686 if (copy_from_user(header, (const void __user *)arg, sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001687 retval = -EFAULT;
1688 break;
1689 }
1690
1691 if (((struct ipa_ioc_query_intf_ext_props *)
Amir Levy479cfdd2017-10-26 12:23:14 +03001692 header)->num_ext_props > IPA_NUM_PROPS_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001693 retval = -EFAULT;
1694 break;
1695 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001696 pre_entry =
1697 ((struct ipa_ioc_query_intf_ext_props *)
1698 header)->num_ext_props;
1699 pyld_sz = sz + pre_entry *
Amir Levy9659e592016-10-27 18:08:27 +03001700 sizeof(struct ipa_ioc_ext_intf_prop);
1701 param = kzalloc(pyld_sz, GFP_KERNEL);
1702 if (!param) {
1703 retval = -ENOMEM;
1704 break;
1705 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001706 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001707 retval = -EFAULT;
1708 break;
1709 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001710 /* add check in case user-space module compromised */
1711 if (unlikely(((struct ipa_ioc_query_intf_ext_props *)
1712 param)->num_ext_props != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301713 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001714 ((struct ipa_ioc_query_intf_ext_props *)
1715 param)->num_ext_props, pre_entry);
1716 retval = -EFAULT;
1717 break;
1718 }
Amir Levy9659e592016-10-27 18:08:27 +03001719 if (ipa3_query_intf_ext_props(
Amir Levy479cfdd2017-10-26 12:23:14 +03001720 (struct ipa_ioc_query_intf_ext_props *)param)) {
Amir Levy9659e592016-10-27 18:08:27 +03001721 retval = -1;
1722 break;
1723 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001724 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001725 retval = -EFAULT;
1726 break;
1727 }
1728 break;
1729 case IPA_IOC_PULL_MSG:
Amir Levy479cfdd2017-10-26 12:23:14 +03001730 if (copy_from_user(header, (const void __user *)arg,
1731 sizeof(struct ipa_msg_meta))) {
Amir Levy9659e592016-10-27 18:08:27 +03001732 retval = -EFAULT;
1733 break;
1734 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001735 pre_entry =
Amir Levy9659e592016-10-27 18:08:27 +03001736 ((struct ipa_msg_meta *)header)->msg_len;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001737 pyld_sz = sizeof(struct ipa_msg_meta) +
1738 pre_entry;
Amir Levy9659e592016-10-27 18:08:27 +03001739 param = kzalloc(pyld_sz, GFP_KERNEL);
1740 if (!param) {
1741 retval = -ENOMEM;
1742 break;
1743 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001744 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001745 retval = -EFAULT;
1746 break;
1747 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001748 /* add check in case user-space module compromised */
1749 if (unlikely(((struct ipa_msg_meta *)param)->msg_len
1750 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301751 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001752 ((struct ipa_msg_meta *)param)->msg_len,
1753 pre_entry);
1754 retval = -EFAULT;
1755 break;
1756 }
Amir Levy9659e592016-10-27 18:08:27 +03001757 if (ipa3_pull_msg((struct ipa_msg_meta *)param,
Amir Levy479cfdd2017-10-26 12:23:14 +03001758 (char *)param + sizeof(struct ipa_msg_meta),
1759 ((struct ipa_msg_meta *)param)->msg_len) !=
1760 ((struct ipa_msg_meta *)param)->msg_len) {
Amir Levy9659e592016-10-27 18:08:27 +03001761 retval = -1;
1762 break;
1763 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001764 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001765 retval = -EFAULT;
1766 break;
1767 }
1768 break;
1769 case IPA_IOC_RM_ADD_DEPENDENCY:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001770 /* deprecate if IPA PM is used */
1771 if (ipa3_ctx->use_ipa_pm)
1772 return 0;
1773
Amir Levy479cfdd2017-10-26 12:23:14 +03001774 if (copy_from_user(&rm_depend, (const void __user *)arg,
1775 sizeof(struct ipa_ioc_rm_dependency))) {
Amir Levy9659e592016-10-27 18:08:27 +03001776 retval = -EFAULT;
1777 break;
1778 }
1779 retval = ipa_rm_add_dependency_from_ioctl(
1780 rm_depend.resource_name, rm_depend.depends_on_name);
1781 break;
1782 case IPA_IOC_RM_DEL_DEPENDENCY:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001783 /* deprecate if IPA PM is used */
1784 if (ipa3_ctx->use_ipa_pm)
1785 return 0;
1786
Amir Levy479cfdd2017-10-26 12:23:14 +03001787 if (copy_from_user(&rm_depend, (const void __user *)arg,
1788 sizeof(struct ipa_ioc_rm_dependency))) {
Amir Levy9659e592016-10-27 18:08:27 +03001789 retval = -EFAULT;
1790 break;
1791 }
1792 retval = ipa_rm_delete_dependency_from_ioctl(
1793 rm_depend.resource_name, rm_depend.depends_on_name);
1794 break;
1795 case IPA_IOC_GENERATE_FLT_EQ:
1796 {
1797 struct ipa_ioc_generate_flt_eq flt_eq;
1798
Amir Levy479cfdd2017-10-26 12:23:14 +03001799 if (copy_from_user(&flt_eq, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001800 sizeof(struct ipa_ioc_generate_flt_eq))) {
1801 retval = -EFAULT;
1802 break;
1803 }
1804 if (ipahal_flt_generate_equation(flt_eq.ip,
1805 &flt_eq.attrib, &flt_eq.eq_attrib)) {
1806 retval = -EFAULT;
1807 break;
1808 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001809 if (copy_to_user((void __user *)arg, &flt_eq,
Amir Levy9659e592016-10-27 18:08:27 +03001810 sizeof(struct ipa_ioc_generate_flt_eq))) {
1811 retval = -EFAULT;
1812 break;
1813 }
1814 break;
1815 }
1816 case IPA_IOC_QUERY_EP_MAPPING:
1817 {
1818 retval = ipa3_get_ep_mapping(arg);
1819 break;
1820 }
1821 case IPA_IOC_QUERY_RT_TBL_INDEX:
Amir Levy479cfdd2017-10-26 12:23:14 +03001822 if (copy_from_user(header, (const void __user *)arg,
1823 sizeof(struct ipa_ioc_get_rt_tbl_indx))) {
Amir Levy9659e592016-10-27 18:08:27 +03001824 retval = -EFAULT;
1825 break;
1826 }
1827 if (ipa3_query_rt_index(
Amir Levy479cfdd2017-10-26 12:23:14 +03001828 (struct ipa_ioc_get_rt_tbl_indx *)header)) {
Amir Levy9659e592016-10-27 18:08:27 +03001829 retval = -EFAULT;
1830 break;
1831 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001832 if (copy_to_user((void __user *)arg, header,
1833 sizeof(struct ipa_ioc_get_rt_tbl_indx))) {
Amir Levy9659e592016-10-27 18:08:27 +03001834 retval = -EFAULT;
1835 break;
1836 }
1837 break;
1838 case IPA_IOC_WRITE_QMAPID:
Amir Levy479cfdd2017-10-26 12:23:14 +03001839 if (copy_from_user(header, (const void __user *)arg,
1840 sizeof(struct ipa_ioc_write_qmapid))) {
Amir Levy9659e592016-10-27 18:08:27 +03001841 retval = -EFAULT;
1842 break;
1843 }
1844 if (ipa3_write_qmap_id((struct ipa_ioc_write_qmapid *)header)) {
1845 retval = -EFAULT;
1846 break;
1847 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001848 if (copy_to_user((void __user *)arg, header,
1849 sizeof(struct ipa_ioc_write_qmapid))) {
Amir Levy9659e592016-10-27 18:08:27 +03001850 retval = -EFAULT;
1851 break;
1852 }
1853 break;
1854 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD:
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05301855 retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD, true);
Amir Levy9659e592016-10-27 18:08:27 +03001856 if (retval) {
1857 IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
1858 break;
1859 }
1860 break;
1861 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL:
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05301862 retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL, true);
Amir Levy9659e592016-10-27 18:08:27 +03001863 if (retval) {
1864 IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
1865 break;
1866 }
1867 break;
1868 case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED:
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05301869 retval = ipa3_send_wan_msg(arg, WAN_EMBMS_CONNECT, false);
Amir Levy9659e592016-10-27 18:08:27 +03001870 if (retval) {
1871 IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
1872 break;
1873 }
1874 break;
1875 case IPA_IOC_ADD_HDR_PROC_CTX:
Amir Levy479cfdd2017-10-26 12:23:14 +03001876 if (copy_from_user(header, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001877 sizeof(struct ipa_ioc_add_hdr_proc_ctx))) {
1878 retval = -EFAULT;
1879 break;
1880 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001881 pre_entry =
1882 ((struct ipa_ioc_add_hdr_proc_ctx *)
1883 header)->num_proc_ctxs;
Amir Levy9659e592016-10-27 18:08:27 +03001884 pyld_sz =
1885 sizeof(struct ipa_ioc_add_hdr_proc_ctx) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001886 pre_entry * sizeof(struct ipa_hdr_proc_ctx_add);
Amir Levy9659e592016-10-27 18:08:27 +03001887 param = kzalloc(pyld_sz, GFP_KERNEL);
1888 if (!param) {
1889 retval = -ENOMEM;
1890 break;
1891 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001892 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001893 retval = -EFAULT;
1894 break;
1895 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001896 /* add check in case user-space module compromised */
1897 if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *)
1898 param)->num_proc_ctxs != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301899 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001900 ((struct ipa_ioc_add_hdr_proc_ctx *)
1901 param)->num_proc_ctxs, pre_entry);
1902 retval = -EFAULT;
1903 break;
1904 }
Amir Levy9659e592016-10-27 18:08:27 +03001905 if (ipa3_add_hdr_proc_ctx(
Skylar Chang68c37d82018-04-07 16:42:36 -07001906 (struct ipa_ioc_add_hdr_proc_ctx *)param, true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001907 retval = -EFAULT;
1908 break;
1909 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001910 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001911 retval = -EFAULT;
1912 break;
1913 }
1914 break;
1915 case IPA_IOC_DEL_HDR_PROC_CTX:
Amir Levy479cfdd2017-10-26 12:23:14 +03001916 if (copy_from_user(header, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001917 sizeof(struct ipa_ioc_del_hdr_proc_ctx))) {
1918 retval = -EFAULT;
1919 break;
1920 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001921 pre_entry =
1922 ((struct ipa_ioc_del_hdr_proc_ctx *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001923 pyld_sz =
1924 sizeof(struct ipa_ioc_del_hdr_proc_ctx) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001925 pre_entry * sizeof(struct ipa_hdr_proc_ctx_del);
Amir Levy9659e592016-10-27 18:08:27 +03001926 param = kzalloc(pyld_sz, GFP_KERNEL);
1927 if (!param) {
1928 retval = -ENOMEM;
1929 break;
1930 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001931 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001932 retval = -EFAULT;
1933 break;
1934 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001935 /* add check in case user-space module compromised */
1936 if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *)
1937 param)->num_hdls != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301938 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001939 ((struct ipa_ioc_del_hdr_proc_ctx *)param)->
1940 num_hdls,
1941 pre_entry);
1942 retval = -EFAULT;
1943 break;
1944 }
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02001945 if (ipa3_del_hdr_proc_ctx_by_user(
1946 (struct ipa_ioc_del_hdr_proc_ctx *)param, true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001947 retval = -EFAULT;
1948 break;
1949 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001950 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001951 retval = -EFAULT;
1952 break;
1953 }
1954 break;
1955
1956 case IPA_IOC_GET_HW_VERSION:
1957 pyld_sz = sizeof(enum ipa_hw_type);
1958 param = kzalloc(pyld_sz, GFP_KERNEL);
1959 if (!param) {
1960 retval = -ENOMEM;
1961 break;
1962 }
1963 memcpy(param, &ipa3_ctx->ipa_hw_type, pyld_sz);
Amir Levy479cfdd2017-10-26 12:23:14 +03001964 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001965 retval = -EFAULT;
1966 break;
1967 }
1968 break;
1969
Amir Levya5361ab2018-05-01 13:25:37 +03001970 case IPA_IOC_GET_VLAN_MODE:
1971 if (copy_from_user(&vlan_mode, (const void __user *)arg,
1972 sizeof(struct ipa_ioc_get_vlan_mode))) {
1973 retval = -EFAULT;
1974 break;
1975 }
1976 retval = ipa3_is_vlan_mode(
1977 vlan_mode.iface,
1978 &is_vlan_mode);
1979 if (retval)
1980 break;
1981
1982 vlan_mode.is_vlan_mode = is_vlan_mode;
1983
1984 if (copy_to_user((void __user *)arg,
1985 &vlan_mode,
1986 sizeof(struct ipa_ioc_get_vlan_mode))) {
1987 retval = -EFAULT;
1988 break;
1989 }
1990 break;
1991
Shihuan Liuc3174f52017-05-04 15:59:13 -07001992 case IPA_IOC_ADD_VLAN_IFACE:
1993 if (ipa3_send_vlan_l2tp_msg(arg, ADD_VLAN_IFACE)) {
1994 retval = -EFAULT;
1995 break;
1996 }
1997 break;
1998
1999 case IPA_IOC_DEL_VLAN_IFACE:
2000 if (ipa3_send_vlan_l2tp_msg(arg, DEL_VLAN_IFACE)) {
2001 retval = -EFAULT;
2002 break;
2003 }
2004 break;
Amir Levy4f8b4832018-06-05 15:48:03 +03002005 case IPA_IOC_ADD_BRIDGE_VLAN_MAPPING:
2006 if (ipa3_send_vlan_l2tp_msg(arg, ADD_BRIDGE_VLAN_MAPPING)) {
2007 retval = -EFAULT;
2008 break;
2009 }
2010 break;
2011 case IPA_IOC_DEL_BRIDGE_VLAN_MAPPING:
2012 if (ipa3_send_vlan_l2tp_msg(arg, DEL_BRIDGE_VLAN_MAPPING)) {
2013 retval = -EFAULT;
2014 break;
2015 }
2016 break;
Shihuan Liuc3174f52017-05-04 15:59:13 -07002017 case IPA_IOC_ADD_L2TP_VLAN_MAPPING:
2018 if (ipa3_send_vlan_l2tp_msg(arg, ADD_L2TP_VLAN_MAPPING)) {
2019 retval = -EFAULT;
2020 break;
2021 }
2022 break;
2023
2024 case IPA_IOC_DEL_L2TP_VLAN_MAPPING:
2025 if (ipa3_send_vlan_l2tp_msg(arg, DEL_L2TP_VLAN_MAPPING)) {
2026 retval = -EFAULT;
2027 break;
2028 }
2029 break;
2030
Skylar Chang68c37d82018-04-07 16:42:36 -07002031 case IPA_IOC_CLEANUP:
2032 /*Route and filter rules will also be clean*/
2033 IPADBG("Got IPA_IOC_CLEANUP\n");
2034 retval = ipa3_reset_hdr(true);
2035 memset(&nat_del, 0, sizeof(nat_del));
2036 nat_del.table_index = 0;
2037 retval = ipa3_nat_del_cmd(&nat_del);
2038 retval = ipa3_clean_modem_rule();
2039 break;
2040
2041 case IPA_IOC_QUERY_WLAN_CLIENT:
2042 IPADBG("Got IPA_IOC_QUERY_WLAN_CLIENT\n");
2043 retval = ipa3_resend_wlan_msg();
2044 break;
2045
Mohammed Javida0f23d92018-09-11 10:50:28 +05302046 case IPA_IOC_GSB_CONNECT:
2047 IPADBG("Got IPA_IOC_GSB_CONNECT\n");
2048 if (ipa3_send_gsb_msg(arg, IPA_GSB_CONNECT)) {
2049 retval = -EFAULT;
2050 break;
2051 }
2052 break;
2053
2054 case IPA_IOC_GSB_DISCONNECT:
2055 IPADBG("Got IPA_IOC_GSB_DISCONNECT\n");
2056 if (ipa3_send_gsb_msg(arg, IPA_GSB_DISCONNECT)) {
2057 retval = -EFAULT;
2058 break;
2059 }
2060 break;
2061
Mohammed Javidd636e0c2019-06-13 16:16:59 +05302062 case IPA_IOC_GET_PHERIPHERAL_EP_INFO:
2063 IPADBG("Got IPA_IOC_GET_EP_INFO\n");
Mohammed Javid3010e192019-08-16 12:38:52 +05302064 if (ipa3_ctx->ipa_config_is_auto == false)
2065 return -ENOTTY;
Mohammed Javidd636e0c2019-06-13 16:16:59 +05302066 if (copy_from_user(&ep_info, (const void __user *)arg,
2067 sizeof(struct ipa_ioc_get_ep_info))) {
2068 IPAERR_RL("copy_from_user fails\n");
2069 retval = -EFAULT;
2070 break;
2071 }
2072
2073 if (ep_info.max_ep_pairs != QUERY_MAX_EP_PAIRS)
2074 IPAERR_RL("unexpected max_ep_pairs %d\n",
2075 ep_info.max_ep_pairs);
2076
2077 if (ep_info.ep_pair_size !=
2078 (QUERY_MAX_EP_PAIRS * sizeof(struct ipa_ep_pair_info)))
2079 IPAERR_RL("unexpected ep_pair_size %d\n",
2080 ep_info.max_ep_pairs);
2081
2082 uptr = ep_info.info;
2083 if (unlikely(!uptr)) {
2084 IPAERR_RL("unexpected NULL info\n");
2085 retval = -EFAULT;
2086 break;
2087 }
2088
2089 param = kzalloc(ep_info.ep_pair_size, GFP_KERNEL);
2090 if (!param) {
2091 IPAERR_RL("kzalloc fails\n");
2092 retval = -ENOMEM;
2093 break;
2094 }
2095
2096 retval = ipa3_get_ep_info(&ep_info, param);
2097 if (retval < 0) {
2098 IPAERR("ipa3_get_ep_info failed\n");
2099 retval = -EFAULT;
2100 break;
2101 }
2102
2103 if (copy_to_user((void __user *)uptr, param,
2104 ep_info.ep_pair_size)) {
2105 IPAERR_RL("copy_to_user fails\n");
2106 retval = -EFAULT;
2107 break;
2108 }
2109
2110 if (copy_to_user((void __user *)arg, &ep_info,
2111 sizeof(struct ipa_ioc_get_ep_info))) {
2112 IPAERR_RL("copy_to_user fails\n");
2113 retval = -EFAULT;
2114 break;
2115 }
2116 break;
2117
Amir Levy479cfdd2017-10-26 12:23:14 +03002118 default:
Amir Levy9659e592016-10-27 18:08:27 +03002119 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2120 return -ENOTTY;
2121 }
2122 kfree(param);
2123 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2124
2125 return retval;
2126}
2127
2128/**
Skylar Chang68c37d82018-04-07 16:42:36 -07002129 * ipa3_setup_dflt_rt_tables() - Setup default routing tables
2130 *
2131 * Return codes:
2132 * 0: success
2133 * -ENOMEM: failed to allocate memory
2134 * -EPERM: failed to add the tables
2135 */
Amir Levy9659e592016-10-27 18:08:27 +03002136int ipa3_setup_dflt_rt_tables(void)
2137{
2138 struct ipa_ioc_add_rt_rule *rt_rule;
2139 struct ipa_rt_rule_add *rt_rule_entry;
2140
2141 rt_rule =
Amir Levy479cfdd2017-10-26 12:23:14 +03002142 kzalloc(sizeof(struct ipa_ioc_add_rt_rule) + 1 *
2143 sizeof(struct ipa_rt_rule_add), GFP_KERNEL);
Amir Levy9659e592016-10-27 18:08:27 +03002144 if (!rt_rule) {
2145 IPAERR("fail to alloc mem\n");
2146 return -ENOMEM;
2147 }
2148 /* setup a default v4 route to point to Apps */
2149 rt_rule->num_rules = 1;
2150 rt_rule->commit = 1;
2151 rt_rule->ip = IPA_IP_v4;
2152 strlcpy(rt_rule->rt_tbl_name, IPA_DFLT_RT_TBL_NAME,
Amir Levy479cfdd2017-10-26 12:23:14 +03002153 IPA_RESOURCE_NAME_MAX);
Amir Levy9659e592016-10-27 18:08:27 +03002154
2155 rt_rule_entry = &rt_rule->rules[0];
2156 rt_rule_entry->at_rear = 1;
2157 rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
2158 rt_rule_entry->rule.hdr_hdl = ipa3_ctx->excp_hdr_hdl;
2159 rt_rule_entry->rule.retain_hdr = 1;
2160
2161 if (ipa3_add_rt_rule(rt_rule)) {
2162 IPAERR("fail to add dflt v4 rule\n");
2163 kfree(rt_rule);
2164 return -EPERM;
2165 }
2166 IPADBG("dflt v4 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
2167 ipa3_ctx->dflt_v4_rt_rule_hdl = rt_rule_entry->rt_rule_hdl;
2168
2169 /* setup a default v6 route to point to A5 */
2170 rt_rule->ip = IPA_IP_v6;
2171 if (ipa3_add_rt_rule(rt_rule)) {
2172 IPAERR("fail to add dflt v6 rule\n");
2173 kfree(rt_rule);
2174 return -EPERM;
2175 }
2176 IPADBG("dflt v6 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
2177 ipa3_ctx->dflt_v6_rt_rule_hdl = rt_rule_entry->rt_rule_hdl;
2178
2179 /*
2180 * because these tables are the very first to be added, they will both
2181 * have the same index (0) which is essential for programming the
2182 * "route" end-point config
2183 */
2184
2185 kfree(rt_rule);
2186
2187 return 0;
2188}
2189
2190static int ipa3_setup_exception_path(void)
2191{
2192 struct ipa_ioc_add_hdr *hdr;
2193 struct ipa_hdr_add *hdr_entry;
2194 struct ipahal_reg_route route = { 0 };
2195 int ret;
2196
2197 /* install the basic exception header */
2198 hdr = kzalloc(sizeof(struct ipa_ioc_add_hdr) + 1 *
2199 sizeof(struct ipa_hdr_add), GFP_KERNEL);
2200 if (!hdr) {
2201 IPAERR("fail to alloc exception hdr\n");
2202 return -ENOMEM;
2203 }
2204 hdr->num_hdrs = 1;
2205 hdr->commit = 1;
2206 hdr_entry = &hdr->hdr[0];
2207
2208 strlcpy(hdr_entry->name, IPA_LAN_RX_HDR_NAME, IPA_RESOURCE_NAME_MAX);
2209 hdr_entry->hdr_len = IPA_LAN_RX_HEADER_LENGTH;
2210
2211 if (ipa3_add_hdr(hdr)) {
2212 IPAERR("fail to add exception hdr\n");
2213 ret = -EPERM;
2214 goto bail;
2215 }
2216
2217 if (hdr_entry->status) {
2218 IPAERR("fail to add exception hdr\n");
2219 ret = -EPERM;
2220 goto bail;
2221 }
2222
2223 ipa3_ctx->excp_hdr_hdl = hdr_entry->hdr_hdl;
2224
2225 /* set the route register to pass exception packets to Apps */
2226 route.route_def_pipe = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS);
2227 route.route_frag_def_pipe = ipa3_get_ep_mapping(
2228 IPA_CLIENT_APPS_LAN_CONS);
2229 route.route_def_hdr_table = !ipa3_ctx->hdr_tbl_lcl;
2230 route.route_def_retain_hdr = 1;
2231
2232 if (ipa3_cfg_route(&route)) {
2233 IPAERR("fail to add exception hdr\n");
2234 ret = -EPERM;
2235 goto bail;
2236 }
2237
2238 ret = 0;
2239bail:
2240 kfree(hdr);
2241 return ret;
2242}
2243
2244static int ipa3_init_smem_region(int memory_region_size,
2245 int memory_region_offset)
2246{
2247 struct ipahal_imm_cmd_dma_shared_mem cmd;
2248 struct ipahal_imm_cmd_pyld *cmd_pyld;
2249 struct ipa3_desc desc;
2250 struct ipa_mem_buffer mem;
2251 int rc;
2252
2253 if (memory_region_size == 0)
2254 return 0;
2255
2256 memset(&desc, 0, sizeof(desc));
2257 memset(&cmd, 0, sizeof(cmd));
2258 memset(&mem, 0, sizeof(mem));
2259
2260 mem.size = memory_region_size;
2261 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
2262 &mem.phys_base, GFP_KERNEL);
2263 if (!mem.base) {
2264 IPAERR("failed to alloc DMA buff of size %d\n", mem.size);
2265 return -ENOMEM;
2266 }
2267
2268 memset(mem.base, 0, mem.size);
2269 cmd.is_read = false;
2270 cmd.skip_pipeline_clear = false;
2271 cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2272 cmd.size = mem.size;
2273 cmd.system_addr = mem.phys_base;
2274 cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
2275 memory_region_offset;
2276 cmd_pyld = ipahal_construct_imm_cmd(
2277 IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
2278 if (!cmd_pyld) {
2279 IPAERR("failed to construct dma_shared_mem imm cmd\n");
2280 return -ENOMEM;
2281 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002282 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002283
2284 rc = ipa3_send_cmd(1, &desc);
2285 if (rc) {
2286 IPAERR("failed to send immediate command (error %d)\n", rc);
2287 rc = -EFAULT;
2288 }
2289
2290 ipahal_destroy_imm_cmd(cmd_pyld);
2291 dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base,
2292 mem.phys_base);
2293
2294 return rc;
2295}
2296
2297/**
Skylar Chang68c37d82018-04-07 16:42:36 -07002298 * ipa3_init_q6_smem() - Initialize Q6 general memory and
2299 * header memory regions in IPA.
2300 *
2301 * Return codes:
2302 * 0: success
2303 * -ENOMEM: failed to allocate dma memory
2304 * -EFAULT: failed to send IPA command to initialize the memory
2305 */
Amir Levy9659e592016-10-27 18:08:27 +03002306int ipa3_init_q6_smem(void)
2307{
2308 int rc;
2309
2310 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
2311
2312 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_size),
2313 IPA_MEM_PART(modem_ofst));
2314 if (rc) {
2315 IPAERR("failed to initialize Modem RAM memory\n");
2316 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2317 return rc;
2318 }
2319
2320 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_hdr_size),
2321 IPA_MEM_PART(modem_hdr_ofst));
2322 if (rc) {
2323 IPAERR("failed to initialize Modem HDRs RAM memory\n");
2324 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2325 return rc;
2326 }
2327
2328 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_hdr_proc_ctx_size),
2329 IPA_MEM_PART(modem_hdr_proc_ctx_ofst));
2330 if (rc) {
2331 IPAERR("failed to initialize Modem proc ctx RAM memory\n");
2332 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2333 return rc;
2334 }
2335
2336 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_comp_decomp_size),
2337 IPA_MEM_PART(modem_comp_decomp_ofst));
2338 if (rc) {
2339 IPAERR("failed to initialize Modem Comp/Decomp RAM memory\n");
2340 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2341 return rc;
2342 }
2343 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2344
2345 return rc;
2346}
2347
2348static void ipa3_destroy_imm(void *user1, int user2)
2349{
2350 ipahal_destroy_imm_cmd(user1);
2351}
2352
2353static void ipa3_q6_pipe_delay(bool delay)
2354{
2355 int client_idx;
2356 int ep_idx;
2357 struct ipa_ep_cfg_ctrl ep_ctrl;
2358
2359 memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
2360 ep_ctrl.ipa_ep_delay = delay;
2361
2362 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2363 if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
2364 ep_idx = ipa3_get_ep_mapping(client_idx);
2365 if (ep_idx == -1)
2366 continue;
2367
2368 ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n,
2369 ep_idx, &ep_ctrl);
2370 }
2371 }
2372}
2373
2374static void ipa3_q6_avoid_holb(void)
2375{
2376 int ep_idx;
2377 int client_idx;
2378 struct ipa_ep_cfg_ctrl ep_suspend;
2379 struct ipa_ep_cfg_holb ep_holb;
2380
2381 memset(&ep_suspend, 0, sizeof(ep_suspend));
2382 memset(&ep_holb, 0, sizeof(ep_holb));
2383
2384 ep_suspend.ipa_ep_suspend = true;
2385 ep_holb.tmr_val = 0;
2386 ep_holb.en = 1;
2387
2388 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2389 if (IPA_CLIENT_IS_Q6_CONS(client_idx)) {
2390 ep_idx = ipa3_get_ep_mapping(client_idx);
2391 if (ep_idx == -1)
2392 continue;
2393
Skylar Changde679dc2017-11-21 10:11:34 -08002394 /* from IPA 4.0 pipe suspend is not supported */
2395 if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
2396 ipahal_write_reg_n_fields(
2397 IPA_ENDP_INIT_CTRL_n,
2398 ep_idx, &ep_suspend);
2399
Amir Levy9659e592016-10-27 18:08:27 +03002400 /*
2401 * ipa3_cfg_ep_holb is not used here because we are
2402 * setting HOLB on Q6 pipes, and from APPS perspective
2403 * they are not valid, therefore, the above function
2404 * will fail.
2405 */
2406 ipahal_write_reg_n_fields(
2407 IPA_ENDP_INIT_HOL_BLOCK_TIMER_n,
2408 ep_idx, &ep_holb);
2409 ipahal_write_reg_n_fields(
2410 IPA_ENDP_INIT_HOL_BLOCK_EN_n,
2411 ep_idx, &ep_holb);
Amir Levy9659e592016-10-27 18:08:27 +03002412 }
2413 }
2414}
2415
Michael Adisumarta0090e542018-03-14 10:44:53 -07002416static void ipa3_halt_q6_gsi_channels(bool prod)
Skylar Chang94692c92017-03-01 09:07:11 -08002417{
2418 int ep_idx;
2419 int client_idx;
2420 const struct ipa_gsi_ep_config *gsi_ep_cfg;
Michael Adisumartaf01e9fd2017-08-31 12:23:51 -07002421 int i;
Skylar Chang94692c92017-03-01 09:07:11 -08002422 int ret;
2423 int code = 0;
2424
Michael Adisumarta0090e542018-03-14 10:44:53 -07002425 /* if prod flag is true, then we halt the producer channels also */
Skylar Chang94692c92017-03-01 09:07:11 -08002426 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
Michael Adisumarta0090e542018-03-14 10:44:53 -07002427 if (IPA_CLIENT_IS_Q6_CONS(client_idx)
2428 || (IPA_CLIENT_IS_Q6_PROD(client_idx) && prod)) {
Skylar Chang94692c92017-03-01 09:07:11 -08002429 ep_idx = ipa3_get_ep_mapping(client_idx);
2430 if (ep_idx == -1)
2431 continue;
2432
Skylar Changc1f15312017-05-09 14:14:32 -07002433 gsi_ep_cfg = ipa3_get_gsi_ep_info(client_idx);
Skylar Chang94692c92017-03-01 09:07:11 -08002434 if (!gsi_ep_cfg) {
2435 IPAERR("failed to get GSI config\n");
2436 ipa_assert();
2437 return;
2438 }
2439
2440 ret = gsi_halt_channel_ee(
2441 gsi_ep_cfg->ipa_gsi_chan_num, gsi_ep_cfg->ee,
2442 &code);
Michael Adisumartaf01e9fd2017-08-31 12:23:51 -07002443 for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY &&
2444 ret == -GSI_STATUS_AGAIN; i++) {
2445 IPADBG(
2446 "ch %d ee %d with code %d\n is busy try again",
2447 gsi_ep_cfg->ipa_gsi_chan_num,
2448 gsi_ep_cfg->ee,
2449 code);
2450 usleep_range(IPA_GSI_CHANNEL_HALT_MIN_SLEEP,
2451 IPA_GSI_CHANNEL_HALT_MAX_SLEEP);
2452 ret = gsi_halt_channel_ee(
2453 gsi_ep_cfg->ipa_gsi_chan_num,
2454 gsi_ep_cfg->ee, &code);
2455 }
Skylar Chang94692c92017-03-01 09:07:11 -08002456 if (ret == GSI_STATUS_SUCCESS)
2457 IPADBG("halted gsi ch %d ee %d with code %d\n",
2458 gsi_ep_cfg->ipa_gsi_chan_num,
2459 gsi_ep_cfg->ee,
2460 code);
2461 else
2462 IPAERR("failed to halt ch %d ee %d code %d\n",
2463 gsi_ep_cfg->ipa_gsi_chan_num,
2464 gsi_ep_cfg->ee,
2465 code);
2466 }
2467 }
2468}
2469
Amir Levy9659e592016-10-27 18:08:27 +03002470static int ipa3_q6_clean_q6_flt_tbls(enum ipa_ip_type ip,
2471 enum ipa_rule_type rlt)
2472{
2473 struct ipa3_desc *desc;
2474 struct ipahal_imm_cmd_dma_shared_mem cmd = {0};
2475 struct ipahal_imm_cmd_pyld **cmd_pyld;
2476 int retval = 0;
2477 int pipe_idx;
2478 int flt_idx = 0;
2479 int num_cmds = 0;
2480 int index;
2481 u32 lcl_addr_mem_part;
2482 u32 lcl_hdr_sz;
2483 struct ipa_mem_buffer mem;
2484
2485 IPADBG("Entry\n");
2486
2487 if ((ip >= IPA_IP_MAX) || (rlt >= IPA_RULE_TYPE_MAX)) {
2488 IPAERR("Input Err: ip=%d ; rlt=%d\n", ip, rlt);
2489 return -EINVAL;
2490 }
2491
2492 /* Up to filtering pipes we have filtering tables */
2493 desc = kcalloc(ipa3_ctx->ep_flt_num, sizeof(struct ipa3_desc),
2494 GFP_KERNEL);
2495 if (!desc) {
2496 IPAERR("failed to allocate memory\n");
2497 return -ENOMEM;
2498 }
2499
2500 cmd_pyld = kcalloc(ipa3_ctx->ep_flt_num,
2501 sizeof(struct ipahal_imm_cmd_pyld *), GFP_KERNEL);
2502 if (!cmd_pyld) {
2503 IPAERR("failed to allocate memory\n");
2504 retval = -ENOMEM;
2505 goto free_desc;
2506 }
2507
2508 if (ip == IPA_IP_v4) {
2509 if (rlt == IPA_RULE_HASHABLE) {
2510 lcl_addr_mem_part = IPA_MEM_PART(v4_flt_hash_ofst);
2511 lcl_hdr_sz = IPA_MEM_PART(v4_flt_hash_size);
2512 } else {
2513 lcl_addr_mem_part = IPA_MEM_PART(v4_flt_nhash_ofst);
2514 lcl_hdr_sz = IPA_MEM_PART(v4_flt_nhash_size);
2515 }
2516 } else {
2517 if (rlt == IPA_RULE_HASHABLE) {
2518 lcl_addr_mem_part = IPA_MEM_PART(v6_flt_hash_ofst);
2519 lcl_hdr_sz = IPA_MEM_PART(v6_flt_hash_size);
2520 } else {
2521 lcl_addr_mem_part = IPA_MEM_PART(v6_flt_nhash_ofst);
2522 lcl_hdr_sz = IPA_MEM_PART(v6_flt_nhash_size);
2523 }
2524 }
2525
2526 retval = ipahal_flt_generate_empty_img(1, lcl_hdr_sz, lcl_hdr_sz,
Amir Levy4dc79be2017-02-01 19:18:35 +02002527 0, &mem, true);
Amir Levy9659e592016-10-27 18:08:27 +03002528 if (retval) {
2529 IPAERR("failed to generate flt single tbl empty img\n");
2530 goto free_cmd_pyld;
2531 }
2532
2533 for (pipe_idx = 0; pipe_idx < ipa3_ctx->ipa_num_pipes; pipe_idx++) {
2534 if (!ipa_is_ep_support_flt(pipe_idx))
2535 continue;
2536
2537 /*
2538 * Iterating over all the filtering pipes which are either
2539 * invalid but connected or connected but not configured by AP.
2540 */
2541 if (!ipa3_ctx->ep[pipe_idx].valid ||
2542 ipa3_ctx->ep[pipe_idx].skip_ep_cfg) {
2543
Amir Levy479cfdd2017-10-26 12:23:14 +03002544 if (num_cmds >= ipa3_ctx->ep_flt_num) {
2545 IPAERR("number of commands is out of range\n");
2546 retval = -ENOBUFS;
2547 goto free_empty_img;
2548 }
2549
Amir Levy9659e592016-10-27 18:08:27 +03002550 cmd.is_read = false;
2551 cmd.skip_pipeline_clear = false;
2552 cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2553 cmd.size = mem.size;
2554 cmd.system_addr = mem.phys_base;
2555 cmd.local_addr =
2556 ipa3_ctx->smem_restricted_bytes +
2557 lcl_addr_mem_part +
2558 ipahal_get_hw_tbl_hdr_width() +
2559 flt_idx * ipahal_get_hw_tbl_hdr_width();
2560 cmd_pyld[num_cmds] = ipahal_construct_imm_cmd(
2561 IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
2562 if (!cmd_pyld[num_cmds]) {
2563 IPAERR("fail construct dma_shared_mem cmd\n");
2564 retval = -ENOMEM;
2565 goto free_empty_img;
2566 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002567 ipa3_init_imm_cmd_desc(&desc[num_cmds],
2568 cmd_pyld[num_cmds]);
2569 ++num_cmds;
Amir Levy9659e592016-10-27 18:08:27 +03002570 }
2571
Amir Levy479cfdd2017-10-26 12:23:14 +03002572 ++flt_idx;
Amir Levy9659e592016-10-27 18:08:27 +03002573 }
2574
2575 IPADBG("Sending %d descriptors for flt tbl clearing\n", num_cmds);
2576 retval = ipa3_send_cmd(num_cmds, desc);
2577 if (retval) {
2578 IPAERR("failed to send immediate command (err %d)\n", retval);
2579 retval = -EFAULT;
2580 }
2581
2582free_empty_img:
2583 ipahal_free_dma_mem(&mem);
2584free_cmd_pyld:
2585 for (index = 0; index < num_cmds; index++)
2586 ipahal_destroy_imm_cmd(cmd_pyld[index]);
2587 kfree(cmd_pyld);
2588free_desc:
2589 kfree(desc);
2590 return retval;
2591}
2592
2593static int ipa3_q6_clean_q6_rt_tbls(enum ipa_ip_type ip,
2594 enum ipa_rule_type rlt)
2595{
2596 struct ipa3_desc *desc;
2597 struct ipahal_imm_cmd_dma_shared_mem cmd = {0};
2598 struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
2599 int retval = 0;
2600 u32 modem_rt_index_lo;
2601 u32 modem_rt_index_hi;
2602 u32 lcl_addr_mem_part;
2603 u32 lcl_hdr_sz;
2604 struct ipa_mem_buffer mem;
2605
2606 IPADBG("Entry\n");
2607
2608 if ((ip >= IPA_IP_MAX) || (rlt >= IPA_RULE_TYPE_MAX)) {
2609 IPAERR("Input Err: ip=%d ; rlt=%d\n", ip, rlt);
2610 return -EINVAL;
2611 }
2612
2613 if (ip == IPA_IP_v4) {
2614 modem_rt_index_lo = IPA_MEM_PART(v4_modem_rt_index_lo);
2615 modem_rt_index_hi = IPA_MEM_PART(v4_modem_rt_index_hi);
2616 if (rlt == IPA_RULE_HASHABLE) {
2617 lcl_addr_mem_part = IPA_MEM_PART(v4_rt_hash_ofst);
2618 lcl_hdr_sz = IPA_MEM_PART(v4_flt_hash_size);
2619 } else {
2620 lcl_addr_mem_part = IPA_MEM_PART(v4_rt_nhash_ofst);
2621 lcl_hdr_sz = IPA_MEM_PART(v4_flt_nhash_size);
2622 }
2623 } else {
2624 modem_rt_index_lo = IPA_MEM_PART(v6_modem_rt_index_lo);
2625 modem_rt_index_hi = IPA_MEM_PART(v6_modem_rt_index_hi);
2626 if (rlt == IPA_RULE_HASHABLE) {
2627 lcl_addr_mem_part = IPA_MEM_PART(v6_rt_hash_ofst);
2628 lcl_hdr_sz = IPA_MEM_PART(v6_flt_hash_size);
2629 } else {
2630 lcl_addr_mem_part = IPA_MEM_PART(v6_rt_nhash_ofst);
2631 lcl_hdr_sz = IPA_MEM_PART(v6_flt_nhash_size);
2632 }
2633 }
2634
2635 retval = ipahal_rt_generate_empty_img(
2636 modem_rt_index_hi - modem_rt_index_lo + 1,
Amir Levy4dc79be2017-02-01 19:18:35 +02002637 lcl_hdr_sz, lcl_hdr_sz, &mem, true);
Amir Levy9659e592016-10-27 18:08:27 +03002638 if (retval) {
2639 IPAERR("fail generate empty rt img\n");
2640 return -ENOMEM;
2641 }
2642
2643 desc = kzalloc(sizeof(struct ipa3_desc), GFP_KERNEL);
2644 if (!desc) {
2645 IPAERR("failed to allocate memory\n");
2646 goto free_empty_img;
2647 }
2648
2649 cmd.is_read = false;
2650 cmd.skip_pipeline_clear = false;
2651 cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2652 cmd.size = mem.size;
2653 cmd.system_addr = mem.phys_base;
2654 cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
2655 lcl_addr_mem_part +
2656 modem_rt_index_lo * ipahal_get_hw_tbl_hdr_width();
2657 cmd_pyld = ipahal_construct_imm_cmd(
2658 IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
2659 if (!cmd_pyld) {
2660 IPAERR("failed to construct dma_shared_mem imm cmd\n");
2661 retval = -ENOMEM;
2662 goto free_desc;
2663 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002664 ipa3_init_imm_cmd_desc(desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002665
2666 IPADBG("Sending 1 descriptor for rt tbl clearing\n");
2667 retval = ipa3_send_cmd(1, desc);
2668 if (retval) {
2669 IPAERR("failed to send immediate command (err %d)\n", retval);
2670 retval = -EFAULT;
2671 }
2672
2673 ipahal_destroy_imm_cmd(cmd_pyld);
2674free_desc:
2675 kfree(desc);
2676free_empty_img:
2677 ipahal_free_dma_mem(&mem);
2678 return retval;
2679}
2680
2681static int ipa3_q6_clean_q6_tables(void)
2682{
2683 struct ipa3_desc *desc;
2684 struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
2685 struct ipahal_imm_cmd_register_write reg_write_cmd = {0};
2686 int retval;
2687 struct ipahal_reg_fltrt_hash_flush flush;
2688 struct ipahal_reg_valmask valmask;
2689
2690 IPADBG("Entry\n");
2691
2692
2693 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v4, IPA_RULE_HASHABLE)) {
2694 IPAERR("failed to clean q6 flt tbls (v4/hashable)\n");
2695 return -EFAULT;
2696 }
2697 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v6, IPA_RULE_HASHABLE)) {
2698 IPAERR("failed to clean q6 flt tbls (v6/hashable)\n");
2699 return -EFAULT;
2700 }
2701 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v4, IPA_RULE_NON_HASHABLE)) {
2702 IPAERR("failed to clean q6 flt tbls (v4/non-hashable)\n");
2703 return -EFAULT;
2704 }
2705 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v6, IPA_RULE_NON_HASHABLE)) {
2706 IPAERR("failed to clean q6 flt tbls (v6/non-hashable)\n");
2707 return -EFAULT;
2708 }
2709
2710 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v4, IPA_RULE_HASHABLE)) {
2711 IPAERR("failed to clean q6 rt tbls (v4/hashable)\n");
2712 return -EFAULT;
2713 }
2714 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v6, IPA_RULE_HASHABLE)) {
2715 IPAERR("failed to clean q6 rt tbls (v6/hashable)\n");
2716 return -EFAULT;
2717 }
2718 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v4, IPA_RULE_NON_HASHABLE)) {
2719 IPAERR("failed to clean q6 rt tbls (v4/non-hashable)\n");
2720 return -EFAULT;
2721 }
2722 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v6, IPA_RULE_NON_HASHABLE)) {
2723 IPAERR("failed to clean q6 rt tbls (v6/non-hashable)\n");
2724 return -EFAULT;
2725 }
2726
2727 /* Flush rules cache */
2728 desc = kzalloc(sizeof(struct ipa3_desc), GFP_KERNEL);
2729 if (!desc) {
2730 IPAERR("failed to allocate memory\n");
2731 return -ENOMEM;
2732 }
2733
2734 flush.v4_flt = true;
2735 flush.v4_rt = true;
2736 flush.v6_flt = true;
2737 flush.v6_rt = true;
2738 ipahal_get_fltrt_hash_flush_valmask(&flush, &valmask);
2739 reg_write_cmd.skip_pipeline_clear = false;
2740 reg_write_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2741 reg_write_cmd.offset = ipahal_get_reg_ofst(IPA_FILT_ROUT_HASH_FLUSH);
2742 reg_write_cmd.value = valmask.val;
2743 reg_write_cmd.value_mask = valmask.mask;
2744 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
2745 &reg_write_cmd, false);
2746 if (!cmd_pyld) {
2747 IPAERR("fail construct register_write imm cmd\n");
2748 retval = -EFAULT;
2749 goto bail_desc;
2750 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002751 ipa3_init_imm_cmd_desc(desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002752
2753 IPADBG("Sending 1 descriptor for tbls flush\n");
2754 retval = ipa3_send_cmd(1, desc);
2755 if (retval) {
2756 IPAERR("failed to send immediate command (err %d)\n", retval);
2757 retval = -EFAULT;
2758 }
2759
2760 ipahal_destroy_imm_cmd(cmd_pyld);
2761
2762bail_desc:
2763 kfree(desc);
2764 IPADBG("Done - retval = %d\n", retval);
2765 return retval;
2766}
2767
2768static int ipa3_q6_set_ex_path_to_apps(void)
2769{
2770 int ep_idx;
2771 int client_idx;
2772 struct ipa3_desc *desc;
2773 int num_descs = 0;
2774 int index;
2775 struct ipahal_imm_cmd_register_write reg_write;
2776 struct ipahal_imm_cmd_pyld *cmd_pyld;
2777 int retval;
Amir Levy9659e592016-10-27 18:08:27 +03002778
2779 desc = kcalloc(ipa3_ctx->ipa_num_pipes, sizeof(struct ipa3_desc),
2780 GFP_KERNEL);
2781 if (!desc) {
2782 IPAERR("failed to allocate memory\n");
2783 return -ENOMEM;
2784 }
2785
2786 /* Set the exception path to AP */
2787 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2788 ep_idx = ipa3_get_ep_mapping(client_idx);
2789 if (ep_idx == -1)
2790 continue;
2791
Skylar Chang53137112017-05-12 17:13:13 -07002792 /* disable statuses for all modem controlled prod pipes */
2793 if (IPA_CLIENT_IS_Q6_PROD(client_idx) ||
2794 (ipa3_ctx->ep[ep_idx].valid &&
Skylar Changd8d8b432018-06-15 10:39:10 -07002795 ipa3_ctx->ep[ep_idx].skip_ep_cfg) ||
2796 (ipa3_ctx->ep[ep_idx].client == IPA_CLIENT_APPS_WAN_PROD
2797 && ipa3_ctx->modem_cfg_emb_pipe_flt)) {
Amir Levy5807be32017-04-19 14:35:12 +03002798 ipa_assert_on(num_descs >= ipa3_ctx->ipa_num_pipes);
2799
Skylar Changd8d8b432018-06-15 10:39:10 -07002800 ipa3_ctx->ep[ep_idx].status.status_en = false;
Amir Levy5807be32017-04-19 14:35:12 +03002801 reg_write.skip_pipeline_clear = false;
2802 reg_write.pipeline_clear_options =
2803 IPAHAL_HPS_CLEAR;
2804 reg_write.offset =
2805 ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n,
2806 ep_idx);
2807 reg_write.value = 0;
2808 reg_write.value_mask = ~0;
2809 cmd_pyld = ipahal_construct_imm_cmd(
2810 IPA_IMM_CMD_REGISTER_WRITE, &reg_write, false);
2811 if (!cmd_pyld) {
2812 IPAERR("fail construct register_write cmd\n");
2813 ipa_assert();
2814 return -EFAULT;
2815 }
2816
Amir Levy479cfdd2017-10-26 12:23:14 +03002817 ipa3_init_imm_cmd_desc(&desc[num_descs], cmd_pyld);
Amir Levy5807be32017-04-19 14:35:12 +03002818 desc[num_descs].callback = ipa3_destroy_imm;
2819 desc[num_descs].user1 = cmd_pyld;
Amir Levy479cfdd2017-10-26 12:23:14 +03002820 ++num_descs;
Amir Levy5807be32017-04-19 14:35:12 +03002821 }
Amir Levy9659e592016-10-27 18:08:27 +03002822 }
2823
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002824 /* Will wait 500msecs for IPA tag process completion */
Amir Levy9659e592016-10-27 18:08:27 +03002825 retval = ipa3_tag_process(desc, num_descs,
2826 msecs_to_jiffies(CLEANUP_TAG_PROCESS_TIMEOUT));
2827 if (retval) {
2828 IPAERR("TAG process failed! (error %d)\n", retval);
2829 /* For timeout error ipa3_destroy_imm cb will destroy user1 */
2830 if (retval != -ETIME) {
2831 for (index = 0; index < num_descs; index++)
2832 if (desc[index].callback)
2833 desc[index].callback(desc[index].user1,
2834 desc[index].user2);
2835 retval = -EINVAL;
2836 }
2837 }
2838
2839 kfree(desc);
2840
2841 return retval;
2842}
2843
2844/**
Skylar Chang68c37d82018-04-07 16:42:36 -07002845 * ipa3_q6_pre_shutdown_cleanup() - A cleanup for all Q6 related configuration
2846 * in IPA HW. This is performed in case of SSR.
2847 *
2848 * This is a mandatory procedure, in case one of the steps fails, the
2849 * AP needs to restart.
2850 */
Amir Levy9659e592016-10-27 18:08:27 +03002851void ipa3_q6_pre_shutdown_cleanup(void)
2852{
2853 IPADBG_LOW("ENTER\n");
2854
2855 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
2856
2857 ipa3_q6_pipe_delay(true);
2858 ipa3_q6_avoid_holb();
Mohammed Javidf109cf62019-07-02 13:16:54 +05302859 if (ipa3_ctx->ipa_config_is_mhi) {
Mohammed Javidd53feb82018-07-19 20:16:39 +05302860 ipa3_set_reset_client_cons_pipe_sus_holb(true,
2861 IPA_CLIENT_MHI_CONS);
Mohammed Javidf109cf62019-07-02 13:16:54 +05302862 if (ipa3_ctx->ipa_config_is_auto)
2863 ipa3_set_reset_client_cons_pipe_sus_holb(true,
2864 IPA_CLIENT_MHI2_CONS);
2865 }
2866
Amir Levy9659e592016-10-27 18:08:27 +03002867 if (ipa3_q6_clean_q6_tables()) {
2868 IPAERR("Failed to clean Q6 tables\n");
2869 BUG();
2870 }
2871 if (ipa3_q6_set_ex_path_to_apps()) {
2872 IPAERR("Failed to redirect exceptions to APPS\n");
2873 BUG();
2874 }
2875 /* Remove delay from Q6 PRODs to avoid pending descriptors
Skylar Chang68c37d82018-04-07 16:42:36 -07002876 * on pipe reset procedure
2877 */
Amir Levy9659e592016-10-27 18:08:27 +03002878 ipa3_q6_pipe_delay(false);
Mohammed Javidd53feb82018-07-19 20:16:39 +05302879 ipa3_set_reset_client_prod_pipe_delay(true,
2880 IPA_CLIENT_USB_PROD);
Mohammed Javid22b54442019-07-01 03:43:21 +05302881 if (ipa3_ctx->ipa_config_is_auto)
2882 ipa3_set_reset_client_prod_pipe_delay(true,
2883 IPA_CLIENT_USB2_PROD);
Mohammed Javidf109cf62019-07-02 13:16:54 +05302884 if (ipa3_ctx->ipa_config_is_mhi) {
Mohammed Javidd53feb82018-07-19 20:16:39 +05302885 ipa3_set_reset_client_prod_pipe_delay(true,
2886 IPA_CLIENT_MHI_PROD);
Mohammed Javidf109cf62019-07-02 13:16:54 +05302887 if (ipa3_ctx->ipa_config_is_auto)
2888 ipa3_set_reset_client_prod_pipe_delay(true,
2889 IPA_CLIENT_MHI2_PROD);
2890 }
Mohammed Javida617b262018-03-19 16:55:00 +05302891
Amir Levy9659e592016-10-27 18:08:27 +03002892 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2893 IPADBG_LOW("Exit with success\n");
2894}
2895
2896/*
2897 * ipa3_q6_post_shutdown_cleanup() - As part of this cleanup
2898 * check if GSI channel related to Q6 producer client is empty.
2899 *
2900 * Q6 GSI channel emptiness is needed to garantee no descriptors with invalid
2901 * info are injected into IPA RX from IPA_IF, while modem is restarting.
2902 */
2903void ipa3_q6_post_shutdown_cleanup(void)
2904{
2905 int client_idx;
Skylar Changc1f15312017-05-09 14:14:32 -07002906 int ep_idx;
Michael Adisumarta0090e542018-03-14 10:44:53 -07002907 bool prod = false;
Amir Levy9659e592016-10-27 18:08:27 +03002908
2909 IPADBG_LOW("ENTER\n");
Amir Levy9659e592016-10-27 18:08:27 +03002910
2911 if (!ipa3_ctx->uc_ctx.uc_loaded) {
2912 IPAERR("uC is not loaded. Skipping\n");
2913 return;
2914 }
2915
Skylar Chang94692c92017-03-01 09:07:11 -08002916 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
2917
2918 /* Handle the issue where SUSPEND was removed for some reason */
2919 ipa3_q6_avoid_holb();
Michael Adisumarta0090e542018-03-14 10:44:53 -07002920
2921 /* halt both prod and cons channels starting at IPAv4 */
2922 if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
2923 prod = true;
2924 ipa3_halt_q6_gsi_channels(prod);
2925 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2926 IPADBG("Exit without consumer check\n");
2927 return;
2928 }
2929
2930 ipa3_halt_q6_gsi_channels(prod);
Skylar Chang94692c92017-03-01 09:07:11 -08002931
Amir Levy9659e592016-10-27 18:08:27 +03002932 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
2933 if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
Skylar Changc1f15312017-05-09 14:14:32 -07002934 ep_idx = ipa3_get_ep_mapping(client_idx);
2935 if (ep_idx == -1)
2936 continue;
2937
Amir Levy9659e592016-10-27 18:08:27 +03002938 if (ipa3_uc_is_gsi_channel_empty(client_idx)) {
2939 IPAERR("fail to validate Q6 ch emptiness %d\n",
2940 client_idx);
2941 BUG();
2942 return;
2943 }
2944 }
2945
2946 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2947 IPADBG_LOW("Exit with success\n");
2948}
2949
2950static inline void ipa3_sram_set_canary(u32 *sram_mmio, int offset)
2951{
2952 /* Set 4 bytes of CANARY before the offset */
2953 sram_mmio[(offset - 4) / 4] = IPA_MEM_CANARY_VAL;
2954}
2955
2956/**
Amir Levy9fadeca2017-04-25 10:18:32 +03002957 * _ipa_init_sram_v3() - Initialize IPA local SRAM.
Amir Levy9659e592016-10-27 18:08:27 +03002958 *
2959 * Return codes: 0 for success, negative value for failure
2960 */
Amir Levy9fadeca2017-04-25 10:18:32 +03002961int _ipa_init_sram_v3(void)
Amir Levy9659e592016-10-27 18:08:27 +03002962{
2963 u32 *ipa_sram_mmio;
2964 unsigned long phys_addr;
2965
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04002966 IPADBG(
2967 "ipa_wrapper_base(0x%08X) ipa_reg_base_ofst(0x%08X) IPA_SRAM_DIRECT_ACCESS_n(0x%08X) smem_restricted_bytes(0x%08X) smem_sz(0x%08X)\n",
2968 ipa3_ctx->ipa_wrapper_base,
2969 ipa3_ctx->ctrl->ipa_reg_base_ofst,
2970 ipahal_get_reg_n_ofst(
2971 IPA_SRAM_DIRECT_ACCESS_n,
2972 ipa3_ctx->smem_restricted_bytes / 4),
2973 ipa3_ctx->smem_restricted_bytes,
2974 ipa3_ctx->smem_sz);
2975
Amir Levy9659e592016-10-27 18:08:27 +03002976 phys_addr = ipa3_ctx->ipa_wrapper_base +
2977 ipa3_ctx->ctrl->ipa_reg_base_ofst +
2978 ipahal_get_reg_n_ofst(IPA_SRAM_DIRECT_ACCESS_n,
2979 ipa3_ctx->smem_restricted_bytes / 4);
2980
2981 ipa_sram_mmio = ioremap(phys_addr, ipa3_ctx->smem_sz);
2982 if (!ipa_sram_mmio) {
2983 IPAERR("fail to ioremap IPA SRAM\n");
2984 return -ENOMEM;
2985 }
2986
2987 /* Consult with ipa_i.h on the location of the CANARY values */
2988 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_flt_hash_ofst) - 4);
2989 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_flt_hash_ofst));
2990 ipa3_sram_set_canary(ipa_sram_mmio,
2991 IPA_MEM_PART(v4_flt_nhash_ofst) - 4);
2992 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_flt_nhash_ofst));
2993 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_flt_hash_ofst) - 4);
2994 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_flt_hash_ofst));
2995 ipa3_sram_set_canary(ipa_sram_mmio,
2996 IPA_MEM_PART(v6_flt_nhash_ofst) - 4);
2997 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_flt_nhash_ofst));
2998 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_hash_ofst) - 4);
2999 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_hash_ofst));
3000 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_nhash_ofst) - 4);
3001 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_nhash_ofst));
3002 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_hash_ofst) - 4);
3003 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_hash_ofst));
3004 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_nhash_ofst) - 4);
3005 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_nhash_ofst));
3006 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_hdr_ofst) - 4);
3007 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_hdr_ofst));
3008 ipa3_sram_set_canary(ipa_sram_mmio,
3009 IPA_MEM_PART(modem_hdr_proc_ctx_ofst) - 4);
3010 ipa3_sram_set_canary(ipa_sram_mmio,
3011 IPA_MEM_PART(modem_hdr_proc_ctx_ofst));
3012 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_ofst) - 4);
3013 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_ofst));
Amir Levy9fadeca2017-04-25 10:18:32 +03003014 ipa3_sram_set_canary(ipa_sram_mmio,
3015 (ipa_get_hw_type() >= IPA_HW_v3_5) ?
3016 IPA_MEM_PART(uc_event_ring_ofst) :
3017 IPA_MEM_PART(end_ofst));
Amir Levy9659e592016-10-27 18:08:27 +03003018
3019 iounmap(ipa_sram_mmio);
3020
3021 return 0;
3022}
3023
3024/**
3025 * _ipa_init_hdr_v3_0() - Initialize IPA header block.
3026 *
3027 * Return codes: 0 for success, negative value for failure
3028 */
3029int _ipa_init_hdr_v3_0(void)
3030{
Amir Levy479cfdd2017-10-26 12:23:14 +03003031 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03003032 struct ipa_mem_buffer mem;
3033 struct ipahal_imm_cmd_hdr_init_local cmd = {0};
3034 struct ipahal_imm_cmd_pyld *cmd_pyld;
3035 struct ipahal_imm_cmd_dma_shared_mem dma_cmd = { 0 };
3036
3037 mem.size = IPA_MEM_PART(modem_hdr_size) + IPA_MEM_PART(apps_hdr_size);
3038 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size, &mem.phys_base,
3039 GFP_KERNEL);
3040 if (!mem.base) {
3041 IPAERR("fail to alloc DMA buff of size %d\n", mem.size);
3042 return -ENOMEM;
3043 }
3044 memset(mem.base, 0, mem.size);
3045
3046 cmd.hdr_table_addr = mem.phys_base;
3047 cmd.size_hdr_table = mem.size;
3048 cmd.hdr_addr = ipa3_ctx->smem_restricted_bytes +
3049 IPA_MEM_PART(modem_hdr_ofst);
3050 cmd_pyld = ipahal_construct_imm_cmd(
3051 IPA_IMM_CMD_HDR_INIT_LOCAL, &cmd, false);
3052 if (!cmd_pyld) {
3053 IPAERR("fail to construct hdr_init_local imm cmd\n");
3054 dma_free_coherent(ipa3_ctx->pdev,
3055 mem.size, mem.base,
3056 mem.phys_base);
3057 return -EFAULT;
3058 }
Amir Levy479cfdd2017-10-26 12:23:14 +03003059 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03003060 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
3061
3062 if (ipa3_send_cmd(1, &desc)) {
3063 IPAERR("fail to send immediate command\n");
3064 ipahal_destroy_imm_cmd(cmd_pyld);
3065 dma_free_coherent(ipa3_ctx->pdev,
3066 mem.size, mem.base,
3067 mem.phys_base);
3068 return -EFAULT;
3069 }
3070
3071 ipahal_destroy_imm_cmd(cmd_pyld);
3072 dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
3073
3074 mem.size = IPA_MEM_PART(modem_hdr_proc_ctx_size) +
3075 IPA_MEM_PART(apps_hdr_proc_ctx_size);
3076 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size, &mem.phys_base,
3077 GFP_KERNEL);
3078 if (!mem.base) {
3079 IPAERR("fail to alloc DMA buff of size %d\n", mem.size);
3080 return -ENOMEM;
3081 }
3082 memset(mem.base, 0, mem.size);
Amir Levy9659e592016-10-27 18:08:27 +03003083
3084 dma_cmd.is_read = false;
3085 dma_cmd.skip_pipeline_clear = false;
3086 dma_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
3087 dma_cmd.system_addr = mem.phys_base;
3088 dma_cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
3089 IPA_MEM_PART(modem_hdr_proc_ctx_ofst);
3090 dma_cmd.size = mem.size;
3091 cmd_pyld = ipahal_construct_imm_cmd(
3092 IPA_IMM_CMD_DMA_SHARED_MEM, &dma_cmd, false);
3093 if (!cmd_pyld) {
3094 IPAERR("fail to construct dma_shared_mem imm\n");
3095 dma_free_coherent(ipa3_ctx->pdev,
3096 mem.size, mem.base,
3097 mem.phys_base);
3098 return -EFAULT;
3099 }
Amir Levy479cfdd2017-10-26 12:23:14 +03003100 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03003101 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
3102
3103 if (ipa3_send_cmd(1, &desc)) {
3104 IPAERR("fail to send immediate command\n");
3105 ipahal_destroy_imm_cmd(cmd_pyld);
3106 dma_free_coherent(ipa3_ctx->pdev,
3107 mem.size,
3108 mem.base,
3109 mem.phys_base);
3110 return -EFAULT;
3111 }
3112 ipahal_destroy_imm_cmd(cmd_pyld);
3113
3114 ipahal_write_reg(IPA_LOCAL_PKT_PROC_CNTXT_BASE, dma_cmd.local_addr);
3115
3116 dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
3117
3118 return 0;
3119}
3120
3121/**
3122 * _ipa_init_rt4_v3() - Initialize IPA routing block for IPv4.
3123 *
3124 * Return codes: 0 for success, negative value for failure
3125 */
3126int _ipa_init_rt4_v3(void)
3127{
Amir Levy479cfdd2017-10-26 12:23:14 +03003128 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03003129 struct ipa_mem_buffer mem;
3130 struct ipahal_imm_cmd_ip_v4_routing_init v4_cmd;
3131 struct ipahal_imm_cmd_pyld *cmd_pyld;
3132 int i;
3133 int rc = 0;
3134
3135 for (i = IPA_MEM_PART(v4_modem_rt_index_lo);
3136 i <= IPA_MEM_PART(v4_modem_rt_index_hi);
3137 i++)
3138 ipa3_ctx->rt_idx_bitmap[IPA_IP_v4] |= (1 << i);
3139 IPADBG("v4 rt bitmap 0x%lx\n", ipa3_ctx->rt_idx_bitmap[IPA_IP_v4]);
3140
3141 rc = ipahal_rt_generate_empty_img(IPA_MEM_PART(v4_rt_num_index),
3142 IPA_MEM_PART(v4_rt_hash_size), IPA_MEM_PART(v4_rt_nhash_size),
Amir Levy4dc79be2017-02-01 19:18:35 +02003143 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03003144 if (rc) {
3145 IPAERR("fail generate empty v4 rt img\n");
3146 return rc;
3147 }
3148
3149 v4_cmd.hash_rules_addr = mem.phys_base;
3150 v4_cmd.hash_rules_size = mem.size;
3151 v4_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
3152 IPA_MEM_PART(v4_rt_hash_ofst);
3153 v4_cmd.nhash_rules_addr = mem.phys_base;
3154 v4_cmd.nhash_rules_size = mem.size;
3155 v4_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
3156 IPA_MEM_PART(v4_rt_nhash_ofst);
3157 IPADBG("putting hashable routing IPv4 rules to phys 0x%x\n",
3158 v4_cmd.hash_local_addr);
3159 IPADBG("putting non-hashable routing IPv4 rules to phys 0x%x\n",
3160 v4_cmd.nhash_local_addr);
3161 cmd_pyld = ipahal_construct_imm_cmd(
3162 IPA_IMM_CMD_IP_V4_ROUTING_INIT, &v4_cmd, false);
3163 if (!cmd_pyld) {
3164 IPAERR("fail construct ip_v4_rt_init imm cmd\n");
3165 rc = -EPERM;
3166 goto free_mem;
3167 }
3168
Amir Levy479cfdd2017-10-26 12:23:14 +03003169 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03003170 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
3171
3172 if (ipa3_send_cmd(1, &desc)) {
3173 IPAERR("fail to send immediate command\n");
3174 rc = -EFAULT;
3175 }
3176
3177 ipahal_destroy_imm_cmd(cmd_pyld);
3178
3179free_mem:
3180 ipahal_free_dma_mem(&mem);
3181 return rc;
3182}
3183
3184/**
3185 * _ipa_init_rt6_v3() - Initialize IPA routing block for IPv6.
3186 *
3187 * Return codes: 0 for success, negative value for failure
3188 */
3189int _ipa_init_rt6_v3(void)
3190{
Amir Levy479cfdd2017-10-26 12:23:14 +03003191 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03003192 struct ipa_mem_buffer mem;
3193 struct ipahal_imm_cmd_ip_v6_routing_init v6_cmd;
3194 struct ipahal_imm_cmd_pyld *cmd_pyld;
3195 int i;
3196 int rc = 0;
3197
3198 for (i = IPA_MEM_PART(v6_modem_rt_index_lo);
3199 i <= IPA_MEM_PART(v6_modem_rt_index_hi);
3200 i++)
3201 ipa3_ctx->rt_idx_bitmap[IPA_IP_v6] |= (1 << i);
3202 IPADBG("v6 rt bitmap 0x%lx\n", ipa3_ctx->rt_idx_bitmap[IPA_IP_v6]);
3203
3204 rc = ipahal_rt_generate_empty_img(IPA_MEM_PART(v6_rt_num_index),
3205 IPA_MEM_PART(v6_rt_hash_size), IPA_MEM_PART(v6_rt_nhash_size),
Amir Levy4dc79be2017-02-01 19:18:35 +02003206 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03003207 if (rc) {
3208 IPAERR("fail generate empty v6 rt img\n");
3209 return rc;
3210 }
3211
3212 v6_cmd.hash_rules_addr = mem.phys_base;
3213 v6_cmd.hash_rules_size = mem.size;
3214 v6_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
3215 IPA_MEM_PART(v6_rt_hash_ofst);
3216 v6_cmd.nhash_rules_addr = mem.phys_base;
3217 v6_cmd.nhash_rules_size = mem.size;
3218 v6_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
3219 IPA_MEM_PART(v6_rt_nhash_ofst);
3220 IPADBG("putting hashable routing IPv6 rules to phys 0x%x\n",
3221 v6_cmd.hash_local_addr);
3222 IPADBG("putting non-hashable routing IPv6 rules to phys 0x%x\n",
3223 v6_cmd.nhash_local_addr);
3224 cmd_pyld = ipahal_construct_imm_cmd(
3225 IPA_IMM_CMD_IP_V6_ROUTING_INIT, &v6_cmd, false);
3226 if (!cmd_pyld) {
3227 IPAERR("fail construct ip_v6_rt_init imm cmd\n");
3228 rc = -EPERM;
3229 goto free_mem;
3230 }
3231
Amir Levy479cfdd2017-10-26 12:23:14 +03003232 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03003233 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
3234
3235 if (ipa3_send_cmd(1, &desc)) {
3236 IPAERR("fail to send immediate command\n");
3237 rc = -EFAULT;
3238 }
3239
3240 ipahal_destroy_imm_cmd(cmd_pyld);
3241
3242free_mem:
3243 ipahal_free_dma_mem(&mem);
3244 return rc;
3245}
3246
3247/**
3248 * _ipa_init_flt4_v3() - Initialize IPA filtering block for IPv4.
3249 *
3250 * Return codes: 0 for success, negative value for failure
3251 */
3252int _ipa_init_flt4_v3(void)
3253{
Amir Levy479cfdd2017-10-26 12:23:14 +03003254 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03003255 struct ipa_mem_buffer mem;
3256 struct ipahal_imm_cmd_ip_v4_filter_init v4_cmd;
3257 struct ipahal_imm_cmd_pyld *cmd_pyld;
3258 int rc;
3259
3260 rc = ipahal_flt_generate_empty_img(ipa3_ctx->ep_flt_num,
3261 IPA_MEM_PART(v4_flt_hash_size),
3262 IPA_MEM_PART(v4_flt_nhash_size), ipa3_ctx->ep_flt_bitmap,
Amir Levy4dc79be2017-02-01 19:18:35 +02003263 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03003264 if (rc) {
3265 IPAERR("fail generate empty v4 flt img\n");
3266 return rc;
3267 }
3268
3269 v4_cmd.hash_rules_addr = mem.phys_base;
3270 v4_cmd.hash_rules_size = mem.size;
3271 v4_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
3272 IPA_MEM_PART(v4_flt_hash_ofst);
3273 v4_cmd.nhash_rules_addr = mem.phys_base;
3274 v4_cmd.nhash_rules_size = mem.size;
3275 v4_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
3276 IPA_MEM_PART(v4_flt_nhash_ofst);
3277 IPADBG("putting hashable filtering IPv4 rules to phys 0x%x\n",
3278 v4_cmd.hash_local_addr);
3279 IPADBG("putting non-hashable filtering IPv4 rules to phys 0x%x\n",
3280 v4_cmd.nhash_local_addr);
3281 cmd_pyld = ipahal_construct_imm_cmd(
3282 IPA_IMM_CMD_IP_V4_FILTER_INIT, &v4_cmd, false);
3283 if (!cmd_pyld) {
3284 IPAERR("fail construct ip_v4_flt_init imm cmd\n");
3285 rc = -EPERM;
3286 goto free_mem;
3287 }
3288
Amir Levy479cfdd2017-10-26 12:23:14 +03003289 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03003290 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
3291
3292 if (ipa3_send_cmd(1, &desc)) {
3293 IPAERR("fail to send immediate command\n");
3294 rc = -EFAULT;
3295 }
3296
3297 ipahal_destroy_imm_cmd(cmd_pyld);
3298
3299free_mem:
3300 ipahal_free_dma_mem(&mem);
3301 return rc;
3302}
3303
3304/**
3305 * _ipa_init_flt6_v3() - Initialize IPA filtering block for IPv6.
3306 *
3307 * Return codes: 0 for success, negative value for failure
3308 */
3309int _ipa_init_flt6_v3(void)
3310{
Amir Levy479cfdd2017-10-26 12:23:14 +03003311 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03003312 struct ipa_mem_buffer mem;
3313 struct ipahal_imm_cmd_ip_v6_filter_init v6_cmd;
3314 struct ipahal_imm_cmd_pyld *cmd_pyld;
3315 int rc;
3316
3317 rc = ipahal_flt_generate_empty_img(ipa3_ctx->ep_flt_num,
3318 IPA_MEM_PART(v6_flt_hash_size),
3319 IPA_MEM_PART(v6_flt_nhash_size), ipa3_ctx->ep_flt_bitmap,
Amir Levy4dc79be2017-02-01 19:18:35 +02003320 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03003321 if (rc) {
3322 IPAERR("fail generate empty v6 flt img\n");
3323 return rc;
3324 }
3325
3326 v6_cmd.hash_rules_addr = mem.phys_base;
3327 v6_cmd.hash_rules_size = mem.size;
3328 v6_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
3329 IPA_MEM_PART(v6_flt_hash_ofst);
3330 v6_cmd.nhash_rules_addr = mem.phys_base;
3331 v6_cmd.nhash_rules_size = mem.size;
3332 v6_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
3333 IPA_MEM_PART(v6_flt_nhash_ofst);
3334 IPADBG("putting hashable filtering IPv6 rules to phys 0x%x\n",
3335 v6_cmd.hash_local_addr);
3336 IPADBG("putting non-hashable filtering IPv6 rules to phys 0x%x\n",
3337 v6_cmd.nhash_local_addr);
3338
3339 cmd_pyld = ipahal_construct_imm_cmd(
3340 IPA_IMM_CMD_IP_V6_FILTER_INIT, &v6_cmd, false);
3341 if (!cmd_pyld) {
3342 IPAERR("fail construct ip_v6_flt_init imm cmd\n");
3343 rc = -EPERM;
3344 goto free_mem;
3345 }
3346
Amir Levy479cfdd2017-10-26 12:23:14 +03003347 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03003348 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
3349
3350 if (ipa3_send_cmd(1, &desc)) {
3351 IPAERR("fail to send immediate command\n");
3352 rc = -EFAULT;
3353 }
3354
3355 ipahal_destroy_imm_cmd(cmd_pyld);
3356
3357free_mem:
3358 ipahal_free_dma_mem(&mem);
3359 return rc;
3360}
3361
3362static int ipa3_setup_flt_hash_tuple(void)
3363{
3364 int pipe_idx;
3365 struct ipahal_reg_hash_tuple tuple;
3366
3367 memset(&tuple, 0, sizeof(struct ipahal_reg_hash_tuple));
3368
3369 for (pipe_idx = 0; pipe_idx < ipa3_ctx->ipa_num_pipes ; pipe_idx++) {
3370 if (!ipa_is_ep_support_flt(pipe_idx))
3371 continue;
3372
3373 if (ipa_is_modem_pipe(pipe_idx))
3374 continue;
3375
3376 if (ipa3_set_flt_tuple_mask(pipe_idx, &tuple)) {
3377 IPAERR("failed to setup pipe %d flt tuple\n", pipe_idx);
3378 return -EFAULT;
3379 }
3380 }
3381
3382 return 0;
3383}
3384
3385static int ipa3_setup_rt_hash_tuple(void)
3386{
3387 int tbl_idx;
3388 struct ipahal_reg_hash_tuple tuple;
3389
3390 memset(&tuple, 0, sizeof(struct ipahal_reg_hash_tuple));
3391
3392 for (tbl_idx = 0;
3393 tbl_idx < max(IPA_MEM_PART(v6_rt_num_index),
3394 IPA_MEM_PART(v4_rt_num_index));
3395 tbl_idx++) {
3396
3397 if (tbl_idx >= IPA_MEM_PART(v4_modem_rt_index_lo) &&
3398 tbl_idx <= IPA_MEM_PART(v4_modem_rt_index_hi))
3399 continue;
3400
3401 if (tbl_idx >= IPA_MEM_PART(v6_modem_rt_index_lo) &&
3402 tbl_idx <= IPA_MEM_PART(v6_modem_rt_index_hi))
3403 continue;
3404
3405 if (ipa3_set_rt_tuple_mask(tbl_idx, &tuple)) {
3406 IPAERR("failed to setup tbl %d rt tuple\n", tbl_idx);
3407 return -EFAULT;
3408 }
3409 }
3410
3411 return 0;
3412}
3413
3414static int ipa3_setup_apps_pipes(void)
3415{
3416 struct ipa_sys_connect_params sys_in;
3417 int result = 0;
3418
3419 if (ipa3_ctx->gsi_ch20_wa) {
3420 IPADBG("Allocating GSI physical channel 20\n");
3421 result = ipa_gsi_ch20_wa();
3422 if (result) {
3423 IPAERR("ipa_gsi_ch20_wa failed %d\n", result);
Ghanim Fodic6b67492017-03-15 14:19:56 +02003424 goto fail_ch20_wa;
Amir Levy9659e592016-10-27 18:08:27 +03003425 }
3426 }
3427
Skylar Changd407e592017-03-30 11:25:30 -07003428 /* allocate the common PROD event ring */
3429 if (ipa3_alloc_common_event_ring()) {
3430 IPAERR("ipa3_alloc_common_event_ring failed.\n");
3431 result = -EPERM;
3432 goto fail_ch20_wa;
3433 }
3434
Amir Levy9659e592016-10-27 18:08:27 +03003435 /* CMD OUT (AP->IPA) */
3436 memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
3437 sys_in.client = IPA_CLIENT_APPS_CMD_PROD;
3438 sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
3439 sys_in.ipa_ep_cfg.mode.mode = IPA_DMA;
3440 sys_in.ipa_ep_cfg.mode.dst = IPA_CLIENT_APPS_LAN_CONS;
3441 if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_cmd)) {
Ghanim Fodic6b67492017-03-15 14:19:56 +02003442 IPAERR(":setup sys pipe (APPS_CMD_PROD) failed.\n");
Amir Levy9659e592016-10-27 18:08:27 +03003443 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003444 goto fail_ch20_wa;
Amir Levy9659e592016-10-27 18:08:27 +03003445 }
3446 IPADBG("Apps to IPA cmd pipe is connected\n");
3447
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04003448 IPADBG("Will initialize SRAM\n");
Amir Levy9659e592016-10-27 18:08:27 +03003449 ipa3_ctx->ctrl->ipa_init_sram();
3450 IPADBG("SRAM initialized\n");
3451
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04003452 IPADBG("Will initialize HDR\n");
Amir Levy9659e592016-10-27 18:08:27 +03003453 ipa3_ctx->ctrl->ipa_init_hdr();
3454 IPADBG("HDR initialized\n");
3455
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04003456 IPADBG("Will initialize V4 RT\n");
Amir Levy9659e592016-10-27 18:08:27 +03003457 ipa3_ctx->ctrl->ipa_init_rt4();
3458 IPADBG("V4 RT initialized\n");
3459
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04003460 IPADBG("Will initialize V6 RT\n");
Amir Levy9659e592016-10-27 18:08:27 +03003461 ipa3_ctx->ctrl->ipa_init_rt6();
3462 IPADBG("V6 RT initialized\n");
3463
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04003464 IPADBG("Will initialize V4 FLT\n");
Amir Levy9659e592016-10-27 18:08:27 +03003465 ipa3_ctx->ctrl->ipa_init_flt4();
3466 IPADBG("V4 FLT initialized\n");
3467
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04003468 IPADBG("Will initialize V6 FLT\n");
Amir Levy9659e592016-10-27 18:08:27 +03003469 ipa3_ctx->ctrl->ipa_init_flt6();
3470 IPADBG("V6 FLT initialized\n");
3471
3472 if (ipa3_setup_flt_hash_tuple()) {
3473 IPAERR(":fail to configure flt hash tuple\n");
3474 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003475 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003476 }
3477 IPADBG("flt hash tuple is configured\n");
3478
3479 if (ipa3_setup_rt_hash_tuple()) {
3480 IPAERR(":fail to configure rt hash tuple\n");
3481 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003482 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003483 }
3484 IPADBG("rt hash tuple is configured\n");
3485
3486 if (ipa3_setup_exception_path()) {
3487 IPAERR(":fail to setup excp path\n");
3488 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003489 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003490 }
3491 IPADBG("Exception path was successfully set");
3492
3493 if (ipa3_setup_dflt_rt_tables()) {
3494 IPAERR(":fail to setup dflt routes\n");
3495 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003496 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003497 }
3498 IPADBG("default routing was set\n");
3499
Ghanim Fodic6b67492017-03-15 14:19:56 +02003500 /* LAN IN (IPA->AP) */
Amir Levy9659e592016-10-27 18:08:27 +03003501 memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
3502 sys_in.client = IPA_CLIENT_APPS_LAN_CONS;
3503 sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
3504 sys_in.notify = ipa3_lan_rx_cb;
3505 sys_in.priv = NULL;
3506 sys_in.ipa_ep_cfg.hdr.hdr_len = IPA_LAN_RX_HEADER_LENGTH;
3507 sys_in.ipa_ep_cfg.hdr_ext.hdr_little_endian = false;
3508 sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid = true;
3509 sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad = IPA_HDR_PAD;
3510 sys_in.ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = false;
3511 sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 0;
3512 sys_in.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2;
3513 sys_in.ipa_ep_cfg.cfg.cs_offload_en = IPA_ENABLE_CS_OFFLOAD_DL;
3514
3515 /**
3516 * ipa_lan_rx_cb() intended to notify the source EP about packet
3517 * being received on the LAN_CONS via calling the source EP call-back.
3518 * There could be a race condition with calling this call-back. Other
3519 * thread may nullify it - e.g. on EP disconnect.
3520 * This lock intended to protect the access to the source EP call-back
3521 */
3522 spin_lock_init(&ipa3_ctx->disconnect_lock);
3523 if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_data_in)) {
Ghanim Fodic6b67492017-03-15 14:19:56 +02003524 IPAERR(":setup sys pipe (LAN_CONS) failed.\n");
Amir Levy9659e592016-10-27 18:08:27 +03003525 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003526 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003527 }
3528
Ghanim Fodic6b67492017-03-15 14:19:56 +02003529 /* LAN OUT (AP->IPA) */
Amir Levy54fe4d32017-03-16 11:21:49 +02003530 if (!ipa3_ctx->ipa_config_is_mhi) {
3531 memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
3532 sys_in.client = IPA_CLIENT_APPS_LAN_PROD;
3533 sys_in.desc_fifo_sz = IPA_SYS_TX_DATA_DESC_FIFO_SZ;
3534 sys_in.ipa_ep_cfg.mode.mode = IPA_BASIC;
3535 if (ipa3_setup_sys_pipe(&sys_in,
3536 &ipa3_ctx->clnt_hdl_data_out)) {
3537 IPAERR(":setup sys pipe (LAN_PROD) failed.\n");
3538 result = -EPERM;
3539 goto fail_lan_data_out;
3540 }
Amir Levy9659e592016-10-27 18:08:27 +03003541 }
3542
3543 return 0;
3544
Ghanim Fodic6b67492017-03-15 14:19:56 +02003545fail_lan_data_out:
Amir Levy9659e592016-10-27 18:08:27 +03003546 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_in);
Ghanim Fodic6b67492017-03-15 14:19:56 +02003547fail_flt_hash_tuple:
Amir Levy9659e592016-10-27 18:08:27 +03003548 if (ipa3_ctx->dflt_v6_rt_rule_hdl)
3549 __ipa3_del_rt_rule(ipa3_ctx->dflt_v6_rt_rule_hdl);
3550 if (ipa3_ctx->dflt_v4_rt_rule_hdl)
3551 __ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl);
3552 if (ipa3_ctx->excp_hdr_hdl)
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02003553 __ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03003554 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
Ghanim Fodic6b67492017-03-15 14:19:56 +02003555fail_ch20_wa:
Amir Levy9659e592016-10-27 18:08:27 +03003556 return result;
3557}
3558
3559static void ipa3_teardown_apps_pipes(void)
3560{
Amir Levy54fe4d32017-03-16 11:21:49 +02003561 if (!ipa3_ctx->ipa_config_is_mhi)
3562 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_out);
Amir Levy9659e592016-10-27 18:08:27 +03003563 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_in);
3564 __ipa3_del_rt_rule(ipa3_ctx->dflt_v6_rt_rule_hdl);
3565 __ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl);
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02003566 __ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03003567 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
3568}
3569
3570#ifdef CONFIG_COMPAT
Amir Levy479cfdd2017-10-26 12:23:14 +03003571
3572static long compat_ipa3_nat_ipv6ct_alloc_table(unsigned long arg,
3573 int (alloc_func)(struct ipa_ioc_nat_ipv6ct_table_alloc *))
3574{
3575 long retval;
3576 struct ipa_ioc_nat_ipv6ct_table_alloc32 table_alloc32;
3577 struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc;
3578
3579 retval = copy_from_user(&table_alloc32, (const void __user *)arg,
3580 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32));
3581 if (retval)
3582 return retval;
3583
3584 table_alloc.size = (size_t)table_alloc32.size;
3585 table_alloc.offset = (off_t)table_alloc32.offset;
3586
3587 retval = alloc_func(&table_alloc);
3588 if (retval)
3589 return retval;
3590
3591 if (table_alloc.offset) {
3592 table_alloc32.offset = (compat_off_t)table_alloc.offset;
3593 retval = copy_to_user((void __user *)arg, &table_alloc32,
3594 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32));
3595 }
3596
3597 return retval;
3598}
3599
Amir Levy9659e592016-10-27 18:08:27 +03003600long compat_ipa3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
3601{
Amir Levy479cfdd2017-10-26 12:23:14 +03003602 long retval = 0;
Amir Levy9659e592016-10-27 18:08:27 +03003603 struct ipa3_ioc_nat_alloc_mem32 nat_mem32;
3604 struct ipa_ioc_nat_alloc_mem nat_mem;
3605
3606 switch (cmd) {
3607 case IPA_IOC_ADD_HDR32:
3608 cmd = IPA_IOC_ADD_HDR;
3609 break;
3610 case IPA_IOC_DEL_HDR32:
3611 cmd = IPA_IOC_DEL_HDR;
3612 break;
3613 case IPA_IOC_ADD_RT_RULE32:
3614 cmd = IPA_IOC_ADD_RT_RULE;
3615 break;
3616 case IPA_IOC_DEL_RT_RULE32:
3617 cmd = IPA_IOC_DEL_RT_RULE;
3618 break;
3619 case IPA_IOC_ADD_FLT_RULE32:
3620 cmd = IPA_IOC_ADD_FLT_RULE;
3621 break;
3622 case IPA_IOC_DEL_FLT_RULE32:
3623 cmd = IPA_IOC_DEL_FLT_RULE;
3624 break;
3625 case IPA_IOC_GET_RT_TBL32:
3626 cmd = IPA_IOC_GET_RT_TBL;
3627 break;
3628 case IPA_IOC_COPY_HDR32:
3629 cmd = IPA_IOC_COPY_HDR;
3630 break;
3631 case IPA_IOC_QUERY_INTF32:
3632 cmd = IPA_IOC_QUERY_INTF;
3633 break;
3634 case IPA_IOC_QUERY_INTF_TX_PROPS32:
3635 cmd = IPA_IOC_QUERY_INTF_TX_PROPS;
3636 break;
3637 case IPA_IOC_QUERY_INTF_RX_PROPS32:
3638 cmd = IPA_IOC_QUERY_INTF_RX_PROPS;
3639 break;
3640 case IPA_IOC_QUERY_INTF_EXT_PROPS32:
3641 cmd = IPA_IOC_QUERY_INTF_EXT_PROPS;
3642 break;
3643 case IPA_IOC_GET_HDR32:
3644 cmd = IPA_IOC_GET_HDR;
3645 break;
3646 case IPA_IOC_ALLOC_NAT_MEM32:
Amir Levy479cfdd2017-10-26 12:23:14 +03003647 retval = copy_from_user(&nat_mem32, (const void __user *)arg,
3648 sizeof(struct ipa3_ioc_nat_alloc_mem32));
3649 if (retval)
3650 return retval;
Amir Levy9659e592016-10-27 18:08:27 +03003651 memcpy(nat_mem.dev_name, nat_mem32.dev_name,
3652 IPA_RESOURCE_NAME_MAX);
3653 nat_mem.size = (size_t)nat_mem32.size;
3654 nat_mem.offset = (off_t)nat_mem32.offset;
3655
3656 /* null terminate the string */
3657 nat_mem.dev_name[IPA_RESOURCE_NAME_MAX - 1] = '\0';
3658
Amir Levy479cfdd2017-10-26 12:23:14 +03003659 retval = ipa3_allocate_nat_device(&nat_mem);
3660 if (retval)
3661 return retval;
Amir Levy9659e592016-10-27 18:08:27 +03003662 nat_mem32.offset = (compat_off_t)nat_mem.offset;
Amir Levy479cfdd2017-10-26 12:23:14 +03003663 retval = copy_to_user((void __user *)arg, &nat_mem32,
3664 sizeof(struct ipa3_ioc_nat_alloc_mem32));
Amir Levy9659e592016-10-27 18:08:27 +03003665 return retval;
Amir Levy479cfdd2017-10-26 12:23:14 +03003666 case IPA_IOC_ALLOC_NAT_TABLE32:
3667 return compat_ipa3_nat_ipv6ct_alloc_table(arg,
3668 ipa3_allocate_nat_table);
3669 case IPA_IOC_ALLOC_IPV6CT_TABLE32:
3670 return compat_ipa3_nat_ipv6ct_alloc_table(arg,
3671 ipa3_allocate_ipv6ct_table);
Amir Levy9659e592016-10-27 18:08:27 +03003672 case IPA_IOC_V4_INIT_NAT32:
3673 cmd = IPA_IOC_V4_INIT_NAT;
3674 break;
Amir Levy479cfdd2017-10-26 12:23:14 +03003675 case IPA_IOC_INIT_IPV6CT_TABLE32:
3676 cmd = IPA_IOC_INIT_IPV6CT_TABLE;
3677 break;
3678 case IPA_IOC_TABLE_DMA_CMD32:
3679 cmd = IPA_IOC_TABLE_DMA_CMD;
Amir Levy9659e592016-10-27 18:08:27 +03003680 break;
3681 case IPA_IOC_V4_DEL_NAT32:
3682 cmd = IPA_IOC_V4_DEL_NAT;
3683 break;
Amir Levy479cfdd2017-10-26 12:23:14 +03003684 case IPA_IOC_DEL_NAT_TABLE32:
3685 cmd = IPA_IOC_DEL_NAT_TABLE;
3686 break;
3687 case IPA_IOC_DEL_IPV6CT_TABLE32:
3688 cmd = IPA_IOC_DEL_IPV6CT_TABLE;
3689 break;
3690 case IPA_IOC_NAT_MODIFY_PDN32:
3691 cmd = IPA_IOC_NAT_MODIFY_PDN;
3692 break;
Amir Levy9659e592016-10-27 18:08:27 +03003693 case IPA_IOC_GET_NAT_OFFSET32:
3694 cmd = IPA_IOC_GET_NAT_OFFSET;
3695 break;
3696 case IPA_IOC_PULL_MSG32:
3697 cmd = IPA_IOC_PULL_MSG;
3698 break;
3699 case IPA_IOC_RM_ADD_DEPENDENCY32:
3700 cmd = IPA_IOC_RM_ADD_DEPENDENCY;
3701 break;
3702 case IPA_IOC_RM_DEL_DEPENDENCY32:
3703 cmd = IPA_IOC_RM_DEL_DEPENDENCY;
3704 break;
3705 case IPA_IOC_GENERATE_FLT_EQ32:
3706 cmd = IPA_IOC_GENERATE_FLT_EQ;
3707 break;
3708 case IPA_IOC_QUERY_RT_TBL_INDEX32:
3709 cmd = IPA_IOC_QUERY_RT_TBL_INDEX;
3710 break;
3711 case IPA_IOC_WRITE_QMAPID32:
3712 cmd = IPA_IOC_WRITE_QMAPID;
3713 break;
3714 case IPA_IOC_MDFY_FLT_RULE32:
3715 cmd = IPA_IOC_MDFY_FLT_RULE;
3716 break;
3717 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD32:
3718 cmd = IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD;
3719 break;
3720 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL32:
3721 cmd = IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL;
3722 break;
3723 case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED32:
3724 cmd = IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED;
3725 break;
3726 case IPA_IOC_MDFY_RT_RULE32:
3727 cmd = IPA_IOC_MDFY_RT_RULE;
3728 break;
3729 case IPA_IOC_COMMIT_HDR:
3730 case IPA_IOC_RESET_HDR:
3731 case IPA_IOC_COMMIT_RT:
3732 case IPA_IOC_RESET_RT:
3733 case IPA_IOC_COMMIT_FLT:
3734 case IPA_IOC_RESET_FLT:
3735 case IPA_IOC_DUMP:
3736 case IPA_IOC_PUT_RT_TBL:
3737 case IPA_IOC_PUT_HDR:
3738 case IPA_IOC_SET_FLT:
3739 case IPA_IOC_QUERY_EP_MAPPING:
3740 break;
3741 default:
3742 return -ENOIOCTLCMD;
3743 }
3744 return ipa3_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
3745}
3746#endif
3747
3748static ssize_t ipa3_write(struct file *file, const char __user *buf,
3749 size_t count, loff_t *ppos);
3750
3751static const struct file_operations ipa3_drv_fops = {
3752 .owner = THIS_MODULE,
3753 .open = ipa3_open,
3754 .read = ipa3_read,
3755 .write = ipa3_write,
3756 .unlocked_ioctl = ipa3_ioctl,
3757#ifdef CONFIG_COMPAT
3758 .compat_ioctl = compat_ipa3_ioctl,
3759#endif
3760};
3761
3762static int ipa3_get_clks(struct device *dev)
3763{
Ghanim Fodi6a831342017-03-07 18:19:15 +02003764 if (ipa3_res.use_bw_vote) {
3765 IPADBG("Vote IPA clock by bw voting via bus scaling driver\n");
3766 ipa3_clk = NULL;
3767 return 0;
3768 }
3769
Amir Levy9659e592016-10-27 18:08:27 +03003770 ipa3_clk = clk_get(dev, "core_clk");
3771 if (IS_ERR(ipa3_clk)) {
3772 if (ipa3_clk != ERR_PTR(-EPROBE_DEFER))
3773 IPAERR("fail to get ipa clk\n");
3774 return PTR_ERR(ipa3_clk);
3775 }
3776 return 0;
3777}
3778
3779/**
3780 * _ipa_enable_clks_v3_0() - Enable IPA clocks.
3781 */
3782void _ipa_enable_clks_v3_0(void)
3783{
Ghanim Fodi6a831342017-03-07 18:19:15 +02003784 IPADBG_LOW("curr_ipa_clk_rate=%d", ipa3_ctx->curr_ipa_clk_rate);
Amir Levy9659e592016-10-27 18:08:27 +03003785 if (ipa3_clk) {
Ghanim Fodi6a831342017-03-07 18:19:15 +02003786 IPADBG_LOW("enabling gcc_ipa_clk\n");
Amir Levy9659e592016-10-27 18:08:27 +03003787 clk_prepare(ipa3_clk);
3788 clk_enable(ipa3_clk);
Amir Levy9659e592016-10-27 18:08:27 +03003789 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
Amir Levy9659e592016-10-27 18:08:27 +03003790 }
3791
Ghanim Fodi6a831342017-03-07 18:19:15 +02003792 ipa3_uc_notify_clk_state(true);
Amir Levy9659e592016-10-27 18:08:27 +03003793}
3794
3795static unsigned int ipa3_get_bus_vote(void)
3796{
3797 unsigned int idx = 1;
3798
Skylar Chang448d8b82017-08-08 17:30:32 -07003799 if (ipa3_ctx->curr_ipa_clk_rate == ipa3_ctx->ctrl->ipa_clk_rate_svs2) {
Amir Levy9659e592016-10-27 18:08:27 +03003800 idx = 1;
3801 } else if (ipa3_ctx->curr_ipa_clk_rate ==
Skylar Chang448d8b82017-08-08 17:30:32 -07003802 ipa3_ctx->ctrl->ipa_clk_rate_svs) {
3803 idx = 2;
3804 } else if (ipa3_ctx->curr_ipa_clk_rate ==
3805 ipa3_ctx->ctrl->ipa_clk_rate_nominal) {
3806 idx = 3;
Amir Levy9659e592016-10-27 18:08:27 +03003807 } else if (ipa3_ctx->curr_ipa_clk_rate ==
3808 ipa3_ctx->ctrl->ipa_clk_rate_turbo) {
3809 idx = ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases - 1;
3810 } else {
3811 WARN_ON(1);
3812 }
Michael Adisumartad8c88e52018-01-05 10:22:38 -08003813 IPADBG_LOW("curr %d idx %d\n", ipa3_ctx->curr_ipa_clk_rate, idx);
Amir Levy9659e592016-10-27 18:08:27 +03003814
3815 return idx;
3816}
3817
3818/**
Skylar Chang68c37d82018-04-07 16:42:36 -07003819 * ipa3_enable_clks() - Turn on IPA clocks
3820 *
3821 * Return codes:
3822 * None
3823 */
Amir Levy9659e592016-10-27 18:08:27 +03003824void ipa3_enable_clks(void)
3825{
Skylar Changefc0a0f2018-03-29 11:17:40 -07003826 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
3827 IPAERR("not supported in this mode\n");
3828 return;
3829 }
3830
Amir Levy9659e592016-10-27 18:08:27 +03003831 IPADBG("enabling IPA clocks and bus voting\n");
3832
Ghanim Fodi6a831342017-03-07 18:19:15 +02003833 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
3834 ipa3_get_bus_vote()))
3835 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03003836
Ghanim Fodi6a831342017-03-07 18:19:15 +02003837 ipa3_ctx->ctrl->ipa3_enable_clks();
Amir Levy9659e592016-10-27 18:08:27 +03003838}
3839
3840
3841/**
3842 * _ipa_disable_clks_v3_0() - Disable IPA clocks.
3843 */
3844void _ipa_disable_clks_v3_0(void)
3845{
Amir Levy9659e592016-10-27 18:08:27 +03003846 ipa3_suspend_apps_pipes(true);
3847 ipa3_uc_notify_clk_state(false);
Ghanim Fodi6a831342017-03-07 18:19:15 +02003848 if (ipa3_clk) {
3849 IPADBG_LOW("disabling gcc_ipa_clk\n");
Amir Levy9659e592016-10-27 18:08:27 +03003850 clk_disable_unprepare(ipa3_clk);
Ghanim Fodi6a831342017-03-07 18:19:15 +02003851 }
Amir Levy9659e592016-10-27 18:08:27 +03003852}
3853
3854/**
Skylar Chang68c37d82018-04-07 16:42:36 -07003855 * ipa3_disable_clks() - Turn off IPA clocks
3856 *
3857 * Return codes:
3858 * None
3859 */
Amir Levy9659e592016-10-27 18:08:27 +03003860void ipa3_disable_clks(void)
3861{
Skylar Changefc0a0f2018-03-29 11:17:40 -07003862 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
3863 IPAERR("not supported in this mode\n");
3864 return;
3865 }
3866
Amir Levy9659e592016-10-27 18:08:27 +03003867 IPADBG("disabling IPA clocks and bus voting\n");
3868
3869 ipa3_ctx->ctrl->ipa3_disable_clks();
3870
Ghanim Fodi6a831342017-03-07 18:19:15 +02003871 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl, 0))
3872 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03003873}
3874
3875/**
3876 * ipa3_start_tag_process() - Send TAG packet and wait for it to come back
3877 *
3878 * This function is called prior to clock gating when active client counter
3879 * is 1. TAG process ensures that there are no packets inside IPA HW that
Amir Levya59ed3f2017-03-05 17:30:55 +02003880 * were not submitted to the IPA client via the transport. During TAG process
3881 * all aggregation frames are (force) closed.
Amir Levy9659e592016-10-27 18:08:27 +03003882 *
3883 * Return codes:
3884 * None
3885 */
3886static void ipa3_start_tag_process(struct work_struct *work)
3887{
3888 int res;
3889
3890 IPADBG("starting TAG process\n");
3891 /* close aggregation frames on all pipes */
3892 res = ipa3_tag_aggr_force_close(-1);
3893 if (res)
3894 IPAERR("ipa3_tag_aggr_force_close failed %d\n", res);
3895 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("TAG_PROCESS");
3896
3897 IPADBG("TAG process done\n");
3898}
3899
3900/**
Skylar Chang68c37d82018-04-07 16:42:36 -07003901 * ipa3_active_clients_log_mod() - Log a modification in the active clients
3902 * reference count
3903 *
3904 * This method logs any modification in the active clients reference count:
3905 * It logs the modification in the circular history buffer
3906 * It logs the modification in the hash table - looking for an entry,
3907 * creating one if needed and deleting one if needed.
3908 *
3909 * @id: ipa3_active client logging info struct to hold the log information
3910 * @inc: a boolean variable to indicate whether the modification is an increase
3911 * or decrease
3912 * @int_ctx: a boolean variable to indicate whether this call is being made from
3913 * an interrupt context and therefore should allocate GFP_ATOMIC memory
3914 *
3915 * Method process:
3916 * - Hash the unique identifier string
3917 * - Find the hash in the table
3918 * 1)If found, increase or decrease the reference count
3919 * 2)If not found, allocate a new hash table entry struct and initialize it
3920 * - Remove and deallocate unneeded data structure
3921 * - Log the call in the circular history buffer (unless it is a simple call)
3922 */
Amir Levy9659e592016-10-27 18:08:27 +03003923void ipa3_active_clients_log_mod(struct ipa_active_client_logging_info *id,
3924 bool inc, bool int_ctx)
3925{
3926 char temp_str[IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN];
3927 unsigned long long t;
3928 unsigned long nanosec_rem;
3929 struct ipa3_active_client_htable_entry *hentry;
3930 struct ipa3_active_client_htable_entry *hfound;
3931 u32 hkey;
3932 char str_to_hash[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
Skylar Chang69ae50e2017-07-31 13:13:29 -07003933 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +03003934
Skylar Chang69ae50e2017-07-31 13:13:29 -07003935 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
3936 int_ctx = true;
Amir Levy9659e592016-10-27 18:08:27 +03003937 hfound = NULL;
3938 memset(str_to_hash, 0, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
3939 strlcpy(str_to_hash, id->id_string, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
Amir Levyd9f51132016-11-14 16:55:35 +02003940 hkey = jhash(str_to_hash, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN,
Amir Levy9659e592016-10-27 18:08:27 +03003941 0);
3942 hash_for_each_possible(ipa3_ctx->ipa3_active_clients_logging.htable,
3943 hentry, list, hkey) {
3944 if (!strcmp(hentry->id_string, id->id_string)) {
3945 hentry->count = hentry->count + (inc ? 1 : -1);
3946 hfound = hentry;
3947 }
3948 }
3949 if (hfound == NULL) {
3950 hentry = NULL;
3951 hentry = kzalloc(sizeof(
3952 struct ipa3_active_client_htable_entry),
3953 int_ctx ? GFP_ATOMIC : GFP_KERNEL);
3954 if (hentry == NULL) {
3955 IPAERR("failed allocating active clients hash entry");
Skylar Chang69ae50e2017-07-31 13:13:29 -07003956 spin_unlock_irqrestore(
3957 &ipa3_ctx->ipa3_active_clients_logging.lock,
3958 flags);
Amir Levy9659e592016-10-27 18:08:27 +03003959 return;
3960 }
3961 hentry->type = id->type;
3962 strlcpy(hentry->id_string, id->id_string,
3963 IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
3964 INIT_HLIST_NODE(&hentry->list);
3965 hentry->count = inc ? 1 : -1;
3966 hash_add(ipa3_ctx->ipa3_active_clients_logging.htable,
3967 &hentry->list, hkey);
3968 } else if (hfound->count == 0) {
3969 hash_del(&hfound->list);
3970 kfree(hfound);
3971 }
3972
3973 if (id->type != SIMPLE) {
3974 t = local_clock();
3975 nanosec_rem = do_div(t, 1000000000) / 1000;
3976 snprintf(temp_str, IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN,
3977 inc ? "[%5lu.%06lu] ^ %s, %s: %d" :
3978 "[%5lu.%06lu] v %s, %s: %d",
3979 (unsigned long)t, nanosec_rem,
3980 id->id_string, id->file, id->line);
3981 ipa3_active_clients_log_insert(temp_str);
3982 }
Skylar Chang69ae50e2017-07-31 13:13:29 -07003983 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
3984 flags);
Amir Levy9659e592016-10-27 18:08:27 +03003985}
3986
3987void ipa3_active_clients_log_dec(struct ipa_active_client_logging_info *id,
3988 bool int_ctx)
3989{
3990 ipa3_active_clients_log_mod(id, false, int_ctx);
3991}
3992
3993void ipa3_active_clients_log_inc(struct ipa_active_client_logging_info *id,
3994 bool int_ctx)
3995{
3996 ipa3_active_clients_log_mod(id, true, int_ctx);
3997}
3998
3999/**
Skylar Chang68c37d82018-04-07 16:42:36 -07004000 * ipa3_inc_client_enable_clks() - Increase active clients counter, and
4001 * enable ipa clocks if necessary
4002 *
4003 * Return codes:
4004 * None
4005 */
Amir Levy9659e592016-10-27 18:08:27 +03004006void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id)
4007{
Skylar Chang242952b2017-07-20 15:04:05 -07004008 int ret;
4009
Amir Levy9659e592016-10-27 18:08:27 +03004010 ipa3_active_clients_log_inc(id, false);
Skylar Chang242952b2017-07-20 15:04:05 -07004011 ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
4012 if (ret) {
4013 IPADBG_LOW("active clients = %d\n",
4014 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
4015 return;
4016 }
4017
4018 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
4019
4020 /* somebody might voted to clocks meanwhile */
4021 ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
4022 if (ret) {
4023 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
4024 IPADBG_LOW("active clients = %d\n",
4025 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
4026 return;
4027 }
4028
4029 ipa3_enable_clks();
4030 atomic_inc(&ipa3_ctx->ipa3_active_clients.cnt);
4031 IPADBG_LOW("active clients = %d\n",
4032 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
4033 ipa3_suspend_apps_pipes(false);
4034 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004035}
4036
4037/**
Skylar Chang68c37d82018-04-07 16:42:36 -07004038 * ipa3_inc_client_enable_clks_no_block() - Only increment the number of active
4039 * clients if no asynchronous actions should be done. Asynchronous actions are
4040 * locking a mutex and waking up IPA HW.
4041 *
4042 * Return codes: 0 for success
4043 * -EPERM if an asynchronous action should have been done
4044 */
Amir Levy9659e592016-10-27 18:08:27 +03004045int ipa3_inc_client_enable_clks_no_block(struct ipa_active_client_logging_info
4046 *id)
4047{
Skylar Chang242952b2017-07-20 15:04:05 -07004048 int ret;
Amir Levy9659e592016-10-27 18:08:27 +03004049
Skylar Chang242952b2017-07-20 15:04:05 -07004050 ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
4051 if (ret) {
4052 ipa3_active_clients_log_inc(id, true);
4053 IPADBG_LOW("active clients = %d\n",
4054 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
4055 return 0;
Amir Levy9659e592016-10-27 18:08:27 +03004056 }
Amir Levy9659e592016-10-27 18:08:27 +03004057
Skylar Chang242952b2017-07-20 15:04:05 -07004058 return -EPERM;
4059}
4060
4061static void __ipa3_dec_client_disable_clks(void)
4062{
4063 int ret;
4064
4065 if (!atomic_read(&ipa3_ctx->ipa3_active_clients.cnt)) {
4066 IPAERR("trying to disable clocks with refcnt is 0!\n");
4067 ipa_assert();
4068 return;
4069 }
4070
4071 ret = atomic_add_unless(&ipa3_ctx->ipa3_active_clients.cnt, -1, 1);
4072 if (ret)
4073 goto bail;
4074
4075 /* seems like this is the only client holding the clocks */
4076 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
4077 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) == 1 &&
4078 ipa3_ctx->tag_process_before_gating) {
4079 ipa3_ctx->tag_process_before_gating = false;
4080 /*
4081 * When TAG process ends, active clients will be
4082 * decreased
4083 */
4084 queue_work(ipa3_ctx->power_mgmt_wq, &ipa3_tag_work);
4085 goto unlock_mutex;
4086 }
4087
4088 /* a different context might increase the clock reference meanwhile */
4089 ret = atomic_sub_return(1, &ipa3_ctx->ipa3_active_clients.cnt);
4090 if (ret > 0)
4091 goto unlock_mutex;
4092 ipa3_disable_clks();
4093
4094unlock_mutex:
4095 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
4096bail:
4097 IPADBG_LOW("active clients = %d\n",
4098 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
Amir Levy9659e592016-10-27 18:08:27 +03004099}
4100
4101/**
4102 * ipa3_dec_client_disable_clks() - Decrease active clients counter
4103 *
4104 * In case that there are no active clients this function also starts
4105 * TAG process. When TAG progress ends ipa clocks will be gated.
4106 * start_tag_process_again flag is set during this function to signal TAG
4107 * process to start again as there was another client that may send data to ipa
4108 *
4109 * Return codes:
4110 * None
4111 */
4112void ipa3_dec_client_disable_clks(struct ipa_active_client_logging_info *id)
4113{
Amir Levy9659e592016-10-27 18:08:27 +03004114 ipa3_active_clients_log_dec(id, false);
Skylar Chang242952b2017-07-20 15:04:05 -07004115 __ipa3_dec_client_disable_clks();
4116}
4117
4118static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work)
4119{
4120 __ipa3_dec_client_disable_clks();
4121}
4122
4123/**
4124 * ipa3_dec_client_disable_clks_no_block() - Decrease active clients counter
4125 * if possible without blocking. If this is the last client then the desrease
4126 * will happen from work queue context.
4127 *
4128 * Return codes:
4129 * None
4130 */
4131void ipa3_dec_client_disable_clks_no_block(
4132 struct ipa_active_client_logging_info *id)
4133{
4134 int ret;
4135
4136 ipa3_active_clients_log_dec(id, true);
4137 ret = atomic_add_unless(&ipa3_ctx->ipa3_active_clients.cnt, -1, 1);
4138 if (ret) {
4139 IPADBG_LOW("active clients = %d\n",
4140 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
4141 return;
Amir Levy9659e592016-10-27 18:08:27 +03004142 }
Skylar Chang242952b2017-07-20 15:04:05 -07004143
4144 /* seems like this is the only client holding the clocks */
4145 queue_work(ipa3_ctx->power_mgmt_wq,
4146 &ipa_dec_clients_disable_clks_on_wq_work);
Amir Levy9659e592016-10-27 18:08:27 +03004147}
4148
4149/**
Skylar Chang68c37d82018-04-07 16:42:36 -07004150 * ipa3_inc_acquire_wakelock() - Increase active clients counter, and
4151 * acquire wakelock if necessary
4152 *
4153 * Return codes:
4154 * None
4155 */
Amir Levy9659e592016-10-27 18:08:27 +03004156void ipa3_inc_acquire_wakelock(void)
4157{
4158 unsigned long flags;
4159
4160 spin_lock_irqsave(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
4161 ipa3_ctx->wakelock_ref_cnt.cnt++;
4162 if (ipa3_ctx->wakelock_ref_cnt.cnt == 1)
4163 __pm_stay_awake(&ipa3_ctx->w_lock);
4164 IPADBG_LOW("active wakelock ref cnt = %d\n",
4165 ipa3_ctx->wakelock_ref_cnt.cnt);
4166 spin_unlock_irqrestore(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
4167}
4168
4169/**
4170 * ipa3_dec_release_wakelock() - Decrease active clients counter
4171 *
4172 * In case if the ref count is 0, release the wakelock.
4173 *
4174 * Return codes:
4175 * None
4176 */
4177void ipa3_dec_release_wakelock(void)
4178{
4179 unsigned long flags;
4180
4181 spin_lock_irqsave(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
4182 ipa3_ctx->wakelock_ref_cnt.cnt--;
4183 IPADBG_LOW("active wakelock ref cnt = %d\n",
4184 ipa3_ctx->wakelock_ref_cnt.cnt);
4185 if (ipa3_ctx->wakelock_ref_cnt.cnt == 0)
4186 __pm_relax(&ipa3_ctx->w_lock);
4187 spin_unlock_irqrestore(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
4188}
4189
Michael Adisumartac06df412017-09-19 10:10:35 -07004190int ipa3_set_clock_plan_from_pm(int idx)
4191{
4192 u32 clk_rate;
4193
Michael Adisumarta9cb4d212018-05-14 18:35:41 -07004194 IPADBG_LOW("idx = %d\n", idx);
4195
4196 if (!ipa3_ctx->enable_clock_scaling) {
4197 ipa3_ctx->ipa3_active_clients.bus_vote_idx = idx;
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08004198 return 0;
Michael Adisumarta9cb4d212018-05-14 18:35:41 -07004199 }
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08004200
Skylar Changefc0a0f2018-03-29 11:17:40 -07004201 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
4202 IPAERR("not supported in this mode\n");
4203 return 0;
4204 }
4205
Michael Adisumartac06df412017-09-19 10:10:35 -07004206 if (idx <= 0 || idx >= ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases) {
4207 IPAERR("bad voltage\n");
4208 return -EINVAL;
4209 }
4210
4211 if (idx == 1)
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08004212 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs2;
Michael Adisumartac06df412017-09-19 10:10:35 -07004213 else if (idx == 2)
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08004214 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
Michael Adisumartac06df412017-09-19 10:10:35 -07004215 else if (idx == 3)
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08004216 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
4217 else if (idx == 4)
Michael Adisumartac06df412017-09-19 10:10:35 -07004218 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
4219 else {
4220 IPAERR("bad voltage\n");
4221 WARN_ON(1);
4222 return -EFAULT;
4223 }
4224
4225 if (clk_rate == ipa3_ctx->curr_ipa_clk_rate) {
4226 IPADBG_LOW("Same voltage\n");
4227 return 0;
4228 }
4229
4230 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
4231 ipa3_ctx->curr_ipa_clk_rate = clk_rate;
4232 ipa3_ctx->ipa3_active_clients.bus_vote_idx = idx;
4233 IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
4234 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) > 0) {
4235 if (ipa3_clk)
4236 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
4237 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
4238 ipa3_get_bus_vote()))
4239 WARN_ON(1);
4240 } else {
4241 IPADBG_LOW("clocks are gated, not setting rate\n");
4242 }
4243 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
4244 IPADBG_LOW("Done\n");
4245
4246 return 0;
4247}
4248
Amir Levy9659e592016-10-27 18:08:27 +03004249int ipa3_set_required_perf_profile(enum ipa_voltage_level floor_voltage,
4250 u32 bandwidth_mbps)
4251{
4252 enum ipa_voltage_level needed_voltage;
4253 u32 clk_rate;
4254
Skylar Changefc0a0f2018-03-29 11:17:40 -07004255 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
4256 IPAERR("not supported in this mode\n");
4257 return 0;
4258 }
4259
Amir Levy9659e592016-10-27 18:08:27 +03004260 IPADBG_LOW("floor_voltage=%d, bandwidth_mbps=%u",
4261 floor_voltage, bandwidth_mbps);
4262
4263 if (floor_voltage < IPA_VOLTAGE_UNSPECIFIED ||
4264 floor_voltage >= IPA_VOLTAGE_MAX) {
4265 IPAERR("bad voltage\n");
4266 return -EINVAL;
4267 }
4268
4269 if (ipa3_ctx->enable_clock_scaling) {
4270 IPADBG_LOW("Clock scaling is enabled\n");
4271 if (bandwidth_mbps >=
4272 ipa3_ctx->ctrl->clock_scaling_bw_threshold_turbo)
4273 needed_voltage = IPA_VOLTAGE_TURBO;
4274 else if (bandwidth_mbps >=
4275 ipa3_ctx->ctrl->clock_scaling_bw_threshold_nominal)
4276 needed_voltage = IPA_VOLTAGE_NOMINAL;
Skylar Chang448d8b82017-08-08 17:30:32 -07004277 else if (bandwidth_mbps >=
4278 ipa3_ctx->ctrl->clock_scaling_bw_threshold_svs)
Amir Levy9659e592016-10-27 18:08:27 +03004279 needed_voltage = IPA_VOLTAGE_SVS;
Skylar Chang448d8b82017-08-08 17:30:32 -07004280 else
4281 needed_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +03004282 } else {
4283 IPADBG_LOW("Clock scaling is disabled\n");
4284 needed_voltage = IPA_VOLTAGE_NOMINAL;
4285 }
4286
4287 needed_voltage = max(needed_voltage, floor_voltage);
4288 switch (needed_voltage) {
Skylar Chang448d8b82017-08-08 17:30:32 -07004289 case IPA_VOLTAGE_SVS2:
4290 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs2;
4291 break;
Amir Levy9659e592016-10-27 18:08:27 +03004292 case IPA_VOLTAGE_SVS:
4293 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
4294 break;
4295 case IPA_VOLTAGE_NOMINAL:
4296 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
4297 break;
4298 case IPA_VOLTAGE_TURBO:
4299 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
4300 break;
4301 default:
4302 IPAERR("bad voltage\n");
4303 WARN_ON(1);
4304 return -EFAULT;
4305 }
4306
4307 if (clk_rate == ipa3_ctx->curr_ipa_clk_rate) {
4308 IPADBG_LOW("Same voltage\n");
4309 return 0;
4310 }
4311
Skylar Chang242952b2017-07-20 15:04:05 -07004312 /* Hold the mutex to avoid race conditions with ipa3_enable_clocks() */
4313 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004314 ipa3_ctx->curr_ipa_clk_rate = clk_rate;
4315 IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
Skylar Chang242952b2017-07-20 15:04:05 -07004316 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) > 0) {
Ghanim Fodi6a831342017-03-07 18:19:15 +02004317 if (ipa3_clk)
4318 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
4319 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
Skylar Chang242952b2017-07-20 15:04:05 -07004320 ipa3_get_bus_vote()))
Ghanim Fodi6a831342017-03-07 18:19:15 +02004321 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03004322 } else {
4323 IPADBG_LOW("clocks are gated, not setting rate\n");
4324 }
Skylar Chang242952b2017-07-20 15:04:05 -07004325 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004326 IPADBG_LOW("Done\n");
Skylar Chang1cbe99c2017-05-01 13:44:03 -07004327
Amir Levy9659e592016-10-27 18:08:27 +03004328 return 0;
4329}
4330
Amir Levya59ed3f2017-03-05 17:30:55 +02004331static void ipa3_process_irq_schedule_rel(void)
Amir Levy9659e592016-10-27 18:08:27 +03004332{
4333 queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
Amir Levya59ed3f2017-03-05 17:30:55 +02004334 &ipa3_transport_release_resource_work,
Amir Levy9659e592016-10-27 18:08:27 +03004335 msecs_to_jiffies(IPA_TRANSPORT_PROD_TIMEOUT_MSEC));
4336}
4337
4338/**
Skylar Chang68c37d82018-04-07 16:42:36 -07004339 * ipa3_suspend_handler() - Handles the suspend interrupt:
4340 * wakes up the suspended peripheral by requesting its consumer
4341 * @interrupt: Interrupt type
4342 * @private_data: The client's private data
4343 * @interrupt_data: Interrupt specific information data
4344 */
Amir Levy9659e592016-10-27 18:08:27 +03004345void ipa3_suspend_handler(enum ipa_irq_type interrupt,
4346 void *private_data,
4347 void *interrupt_data)
4348{
4349 enum ipa_rm_resource_name resource;
4350 u32 suspend_data =
4351 ((struct ipa_tx_suspend_irq_data *)interrupt_data)->endpoints;
4352 u32 bmsk = 1;
4353 u32 i = 0;
4354 int res;
4355 struct ipa_ep_cfg_holb holb_cfg;
Michael Adisumarta3e350812017-09-18 14:54:36 -07004356 u32 pipe_bitmask = 0;
Amir Levy9659e592016-10-27 18:08:27 +03004357
4358 IPADBG("interrupt=%d, interrupt_data=%u\n",
4359 interrupt, suspend_data);
4360 memset(&holb_cfg, 0, sizeof(holb_cfg));
4361 holb_cfg.tmr_val = 0;
4362
Michael Adisumarta3e350812017-09-18 14:54:36 -07004363 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++, bmsk = bmsk << 1) {
Amir Levy9659e592016-10-27 18:08:27 +03004364 if ((suspend_data & bmsk) && (ipa3_ctx->ep[i].valid)) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07004365 if (ipa3_ctx->use_ipa_pm) {
4366 pipe_bitmask |= bmsk;
4367 continue;
4368 }
Amir Levy9659e592016-10-27 18:08:27 +03004369 if (IPA_CLIENT_IS_APPS_CONS(ipa3_ctx->ep[i].client)) {
4370 /*
4371 * pipe will be unsuspended as part of
4372 * enabling IPA clocks
4373 */
Skylar Chang0d06bb12017-02-24 11:22:03 -08004374 mutex_lock(&ipa3_ctx->transport_pm.
4375 transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004376 if (!atomic_read(
4377 &ipa3_ctx->transport_pm.dec_clients)
4378 ) {
4379 IPA_ACTIVE_CLIENTS_INC_EP(
4380 ipa3_ctx->ep[i].client);
4381 IPADBG_LOW("Pipes un-suspended.\n");
4382 IPADBG_LOW("Enter poll mode.\n");
4383 atomic_set(
4384 &ipa3_ctx->transport_pm.dec_clients,
4385 1);
Skylar Chang9e3b6492017-11-07 09:49:48 -08004386 /*
4387 * acquire wake lock as long as suspend
4388 * vote is held
4389 */
4390 ipa3_inc_acquire_wakelock();
Amir Levya59ed3f2017-03-05 17:30:55 +02004391 ipa3_process_irq_schedule_rel();
Amir Levy9659e592016-10-27 18:08:27 +03004392 }
Skylar Chang0d06bb12017-02-24 11:22:03 -08004393 mutex_unlock(&ipa3_ctx->transport_pm.
4394 transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004395 } else {
4396 resource = ipa3_get_rm_resource_from_ep(i);
4397 res =
4398 ipa_rm_request_resource_with_timer(resource);
4399 if (res == -EPERM &&
4400 IPA_CLIENT_IS_CONS(
4401 ipa3_ctx->ep[i].client)) {
4402 holb_cfg.en = 1;
4403 res = ipa3_cfg_ep_holb_by_client(
4404 ipa3_ctx->ep[i].client, &holb_cfg);
4405 if (res) {
4406 IPAERR("holb en fail, stall\n");
4407 BUG();
4408 }
4409 }
4410 }
4411 }
Michael Adisumarta3e350812017-09-18 14:54:36 -07004412 }
4413 if (ipa3_ctx->use_ipa_pm) {
4414 res = ipa_pm_handle_suspend(pipe_bitmask);
4415 if (res) {
4416 IPAERR("ipa_pm_handle_suspend failed %d\n", res);
4417 return;
4418 }
Amir Levy9659e592016-10-27 18:08:27 +03004419 }
4420}
4421
4422/**
Skylar Chang68c37d82018-04-07 16:42:36 -07004423 * ipa3_restore_suspend_handler() - restores the original suspend IRQ handler
4424 * as it was registered in the IPA init sequence.
4425 * Return codes:
4426 * 0: success
4427 * -EPERM: failed to remove current handler or failed to add original handler
4428 */
Amir Levy9659e592016-10-27 18:08:27 +03004429int ipa3_restore_suspend_handler(void)
4430{
4431 int result = 0;
4432
4433 result = ipa3_remove_interrupt_handler(IPA_TX_SUSPEND_IRQ);
4434 if (result) {
4435 IPAERR("remove handler for suspend interrupt failed\n");
4436 return -EPERM;
4437 }
4438
4439 result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
4440 ipa3_suspend_handler, false, NULL);
4441 if (result) {
4442 IPAERR("register handler for suspend interrupt failed\n");
4443 result = -EPERM;
4444 }
4445
4446 IPADBG("suspend handler successfully restored\n");
4447
4448 return result;
4449}
4450
4451static int ipa3_apps_cons_release_resource(void)
4452{
4453 return 0;
4454}
4455
4456static int ipa3_apps_cons_request_resource(void)
4457{
4458 return 0;
4459}
4460
Amir Levya59ed3f2017-03-05 17:30:55 +02004461static void ipa3_transport_release_resource(struct work_struct *work)
Amir Levy9659e592016-10-27 18:08:27 +03004462{
Sridhar Ancha99b505b2016-04-21 23:11:10 +05304463 mutex_lock(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004464 /* check whether still need to decrease client usage */
4465 if (atomic_read(&ipa3_ctx->transport_pm.dec_clients)) {
4466 if (atomic_read(&ipa3_ctx->transport_pm.eot_activity)) {
4467 IPADBG("EOT pending Re-scheduling\n");
Amir Levya59ed3f2017-03-05 17:30:55 +02004468 ipa3_process_irq_schedule_rel();
Amir Levy9659e592016-10-27 18:08:27 +03004469 } else {
4470 atomic_set(&ipa3_ctx->transport_pm.dec_clients, 0);
Skylar Chang9e3b6492017-11-07 09:49:48 -08004471 ipa3_dec_release_wakelock();
Amir Levya59ed3f2017-03-05 17:30:55 +02004472 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("TRANSPORT_RESOURCE");
Amir Levy9659e592016-10-27 18:08:27 +03004473 }
4474 }
4475 atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
Sridhar Ancha99b505b2016-04-21 23:11:10 +05304476 mutex_unlock(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004477}
4478
4479int ipa3_create_apps_resource(void)
4480{
4481 struct ipa_rm_create_params apps_cons_create_params;
4482 struct ipa_rm_perf_profile profile;
4483 int result = 0;
4484
4485 memset(&apps_cons_create_params, 0,
4486 sizeof(apps_cons_create_params));
4487 apps_cons_create_params.name = IPA_RM_RESOURCE_APPS_CONS;
4488 apps_cons_create_params.request_resource =
4489 ipa3_apps_cons_request_resource;
4490 apps_cons_create_params.release_resource =
4491 ipa3_apps_cons_release_resource;
4492 result = ipa_rm_create_resource(&apps_cons_create_params);
4493 if (result) {
4494 IPAERR("ipa_rm_create_resource failed\n");
4495 return result;
4496 }
4497
4498 profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
4499 ipa_rm_set_perf_profile(IPA_RM_RESOURCE_APPS_CONS, &profile);
4500
4501 return result;
4502}
4503
4504/**
4505 * ipa3_init_interrupts() - Register to IPA IRQs
4506 *
4507 * Return codes: 0 in success, negative in failure
4508 *
4509 */
4510int ipa3_init_interrupts(void)
4511{
4512 int result;
4513
4514 /*register IPA IRQ handler*/
4515 result = ipa3_interrupts_init(ipa3_res.ipa_irq, 0,
Skylar Changefc0a0f2018-03-29 11:17:40 -07004516 &ipa3_ctx->master_pdev->dev);
Amir Levy9659e592016-10-27 18:08:27 +03004517 if (result) {
4518 IPAERR("ipa interrupts initialization failed\n");
4519 return -ENODEV;
4520 }
4521
4522 /*add handler for suspend interrupt*/
4523 result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
4524 ipa3_suspend_handler, false, NULL);
4525 if (result) {
4526 IPAERR("register handler for suspend interrupt failed\n");
4527 result = -ENODEV;
4528 goto fail_add_interrupt_handler;
4529 }
4530
4531 return 0;
4532
4533fail_add_interrupt_handler:
Skylar Changefc0a0f2018-03-29 11:17:40 -07004534 free_irq(ipa3_res.ipa_irq, &ipa3_ctx->master_pdev->dev);
Amir Levy9659e592016-10-27 18:08:27 +03004535 return result;
4536}
4537
4538/**
4539 * ipa3_destroy_flt_tbl_idrs() - destroy the idr structure for flt tables
4540 * The idr strcuture per filtering table is intended for rule id generation
4541 * per filtering rule.
4542 */
4543static void ipa3_destroy_flt_tbl_idrs(void)
4544{
4545 int i;
4546 struct ipa3_flt_tbl *flt_tbl;
4547
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004548 idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
4549 idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
4550
Amir Levy9659e592016-10-27 18:08:27 +03004551 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4552 if (!ipa_is_ep_support_flt(i))
4553 continue;
4554
4555 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004556 flt_tbl->rule_ids = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004557 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004558 flt_tbl->rule_ids = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004559 }
4560}
4561
4562static void ipa3_freeze_clock_vote_and_notify_modem(void)
4563{
4564 int res;
Amir Levy9659e592016-10-27 18:08:27 +03004565 struct ipa_active_client_logging_info log_info;
4566
4567 if (ipa3_ctx->smp2p_info.res_sent)
4568 return;
4569
Skylar Change1209942017-02-02 14:26:38 -08004570 if (ipa3_ctx->smp2p_info.out_base_id == 0) {
4571 IPAERR("smp2p out gpio not assigned\n");
4572 return;
4573 }
4574
Amir Levy9659e592016-10-27 18:08:27 +03004575 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "FREEZE_VOTE");
4576 res = ipa3_inc_client_enable_clks_no_block(&log_info);
4577 if (res)
Skylar Change1209942017-02-02 14:26:38 -08004578 ipa3_ctx->smp2p_info.ipa_clk_on = false;
Amir Levy9659e592016-10-27 18:08:27 +03004579 else
Skylar Change1209942017-02-02 14:26:38 -08004580 ipa3_ctx->smp2p_info.ipa_clk_on = true;
Amir Levy9659e592016-10-27 18:08:27 +03004581
Skylar Change1209942017-02-02 14:26:38 -08004582 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4583 IPA_GPIO_OUT_CLK_VOTE_IDX,
4584 ipa3_ctx->smp2p_info.ipa_clk_on);
4585 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4586 IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 1);
Amir Levy9659e592016-10-27 18:08:27 +03004587
Skylar Change1209942017-02-02 14:26:38 -08004588 ipa3_ctx->smp2p_info.res_sent = true;
4589 IPADBG("IPA clocks are %s\n",
4590 ipa3_ctx->smp2p_info.ipa_clk_on ? "ON" : "OFF");
4591}
4592
4593void ipa3_reset_freeze_vote(void)
4594{
4595 if (ipa3_ctx->smp2p_info.res_sent == false)
4596 return;
4597
4598 if (ipa3_ctx->smp2p_info.ipa_clk_on)
4599 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("FREEZE_VOTE");
4600
4601 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4602 IPA_GPIO_OUT_CLK_VOTE_IDX, 0);
4603 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4604 IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 0);
4605
4606 ipa3_ctx->smp2p_info.res_sent = false;
4607 ipa3_ctx->smp2p_info.ipa_clk_on = false;
Amir Levy9659e592016-10-27 18:08:27 +03004608}
4609
4610static int ipa3_panic_notifier(struct notifier_block *this,
4611 unsigned long event, void *ptr)
4612{
4613 int res;
4614
4615 ipa3_freeze_clock_vote_and_notify_modem();
4616
4617 IPADBG("Calling uC panic handler\n");
4618 res = ipa3_uc_panic_notifier(this, event, ptr);
4619 if (res)
4620 IPAERR("uC panic handler failed %d\n", res);
4621
Michael Adisumartaedba22d2018-04-19 12:28:33 -07004622 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) != 0)
Michael Adisumartac50b8002018-06-13 15:21:07 -07004623 ipahal_print_all_regs(false);
Michael Adisumartaedba22d2018-04-19 12:28:33 -07004624
Amir Levy9659e592016-10-27 18:08:27 +03004625 return NOTIFY_DONE;
4626}
4627
4628static struct notifier_block ipa3_panic_blk = {
4629 .notifier_call = ipa3_panic_notifier,
4630 /* IPA panic handler needs to run before modem shuts down */
4631 .priority = INT_MAX,
4632};
4633
4634static void ipa3_register_panic_hdlr(void)
4635{
4636 atomic_notifier_chain_register(&panic_notifier_list,
4637 &ipa3_panic_blk);
4638}
4639
4640static void ipa3_trigger_ipa_ready_cbs(void)
4641{
4642 struct ipa3_ready_cb_info *info;
4643
4644 mutex_lock(&ipa3_ctx->lock);
4645
4646 /* Call all the CBs */
4647 list_for_each_entry(info, &ipa3_ctx->ipa_ready_cb_list, link)
4648 if (info->ready_cb)
4649 info->ready_cb(info->user_data);
4650
4651 mutex_unlock(&ipa3_ctx->lock);
4652}
4653
4654static int ipa3_gsi_pre_fw_load_init(void)
4655{
4656 int result;
4657
4658 result = gsi_configure_regs(ipa3_res.transport_mem_base,
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04004659 ipa3_res.transport_mem_size,
4660 ipa3_res.ipa_mem_base);
Amir Levy9659e592016-10-27 18:08:27 +03004661 if (result) {
4662 IPAERR("Failed to configure GSI registers\n");
4663 return -EINVAL;
4664 }
4665
4666 return 0;
4667}
4668
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004669static void ipa3_uc_is_loaded(void)
4670{
4671 IPADBG("\n");
4672 complete_all(&ipa3_ctx->uc_loaded_completion_obj);
4673}
4674
Amir Levy41644242016-11-03 15:38:09 +02004675static enum gsi_ver ipa3_get_gsi_ver(enum ipa_hw_type ipa_hw_type)
4676{
4677 enum gsi_ver gsi_ver;
4678
4679 switch (ipa_hw_type) {
4680 case IPA_HW_v3_0:
4681 case IPA_HW_v3_1:
4682 gsi_ver = GSI_VER_1_0;
4683 break;
4684 case IPA_HW_v3_5:
4685 gsi_ver = GSI_VER_1_2;
4686 break;
4687 case IPA_HW_v3_5_1:
4688 gsi_ver = GSI_VER_1_3;
4689 break;
Michael Adisumarta891a4ff2017-05-16 16:40:06 -07004690 case IPA_HW_v4_0:
4691 gsi_ver = GSI_VER_2_0;
4692 break;
Amir Levy41644242016-11-03 15:38:09 +02004693 default:
4694 IPAERR("No GSI version for ipa type %d\n", ipa_hw_type);
4695 WARN_ON(1);
4696 gsi_ver = GSI_VER_ERR;
4697 }
4698
4699 IPADBG("GSI version %d\n", gsi_ver);
4700
4701 return gsi_ver;
4702}
4703
Amir Levy9659e592016-10-27 18:08:27 +03004704/**
4705 * ipa3_post_init() - Initialize the IPA Driver (Part II).
4706 * This part contains all initialization which requires interaction with
Amir Levya59ed3f2017-03-05 17:30:55 +02004707 * IPA HW (via GSI).
Amir Levy9659e592016-10-27 18:08:27 +03004708 *
4709 * @resource_p: contain platform specific values from DST file
4710 * @pdev: The platform device structure representing the IPA driver
4711 *
4712 * Function initialization process:
Amir Levy54fe4d32017-03-16 11:21:49 +02004713 * - Initialize endpoints bitmaps
4714 * - Initialize resource groups min and max values
4715 * - Initialize filtering lists heads and idr
4716 * - Initialize interrupts
Amir Levya59ed3f2017-03-05 17:30:55 +02004717 * - Register GSI
Amir Levy9659e592016-10-27 18:08:27 +03004718 * - Setup APPS pipes
4719 * - Initialize tethering bridge
4720 * - Initialize IPA debugfs
4721 * - Initialize IPA uC interface
4722 * - Initialize WDI interface
4723 * - Initialize USB interface
4724 * - Register for panic handler
4725 * - Trigger IPA ready callbacks (to all subscribers)
4726 * - Trigger IPA completion object (to all who wait on it)
4727 */
4728static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p,
4729 struct device *ipa_dev)
4730{
4731 int result;
Amir Levy9659e592016-10-27 18:08:27 +03004732 struct gsi_per_props gsi_props;
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004733 struct ipa3_uc_hdlrs uc_hdlrs = { 0 };
Amir Levy54fe4d32017-03-16 11:21:49 +02004734 struct ipa3_flt_tbl *flt_tbl;
4735 int i;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004736 struct idr *idr;
Amir Levy54fe4d32017-03-16 11:21:49 +02004737
Utkarsh Saxenaded78142017-05-03 14:04:30 +05304738 if (ipa3_ctx == NULL) {
4739 IPADBG("IPA driver haven't initialized\n");
4740 return -ENXIO;
4741 }
4742
4743 /* Prevent consequent calls from trying to load the FW again. */
4744 if (ipa3_ctx->ipa_initialization_complete)
4745 return 0;
Mohammed Javidc6db3362018-02-13 13:41:38 +05304746
4747 IPADBG("active clients = %d\n",
4748 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
Skylar Chang40430532017-07-06 14:31:57 -07004749 /* move proxy vote for modem on ipa3_post_init */
Mohammed Javidc6db3362018-02-13 13:41:38 +05304750 if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0)
4751 ipa3_proxy_clk_vote();
Utkarsh Saxenaded78142017-05-03 14:04:30 +05304752
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04004753 /*
4754 * SMMU was already attached if used, safe to do allocations
4755 *
4756 * NOTE WELL: On an emulation system, this allocation is done
4757 * in ipa3_pre_init()
4758 */
4759 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_EMULATION) {
4760 if (ipahal_init(ipa3_ctx->ipa_hw_type, ipa3_ctx->mmio,
4761 ipa3_ctx->pdev)) {
4762 IPAERR("fail to init ipahal\n");
4763 result = -EFAULT;
4764 goto fail_ipahal;
4765 }
Skylar Changefc0a0f2018-03-29 11:17:40 -07004766 }
4767
4768 result = ipa3_init_hw();
4769 if (result) {
4770 IPAERR(":error initializing HW\n");
4771 result = -ENODEV;
4772 goto fail_init_hw;
4773 }
4774 IPADBG("IPA HW initialization sequence completed");
4775
4776 ipa3_ctx->ipa_num_pipes = ipa3_get_num_pipes();
4777 if (ipa3_ctx->ipa_num_pipes > IPA3_MAX_NUM_PIPES) {
4778 IPAERR("IPA has more pipes then supported has %d, max %d\n",
4779 ipa3_ctx->ipa_num_pipes, IPA3_MAX_NUM_PIPES);
4780 result = -ENODEV;
4781 goto fail_init_hw;
4782 }
4783
4784 ipa3_ctx->ctrl->ipa_sram_read_settings();
4785 IPADBG("SRAM, size: 0x%x, restricted bytes: 0x%x\n",
4786 ipa3_ctx->smem_sz, ipa3_ctx->smem_restricted_bytes);
4787
4788 IPADBG("hdr_lcl=%u ip4_rt_hash=%u ip4_rt_nonhash=%u\n",
4789 ipa3_ctx->hdr_tbl_lcl, ipa3_ctx->ip4_rt_tbl_hash_lcl,
4790 ipa3_ctx->ip4_rt_tbl_nhash_lcl);
4791
4792 IPADBG("ip6_rt_hash=%u ip6_rt_nonhash=%u\n",
4793 ipa3_ctx->ip6_rt_tbl_hash_lcl, ipa3_ctx->ip6_rt_tbl_nhash_lcl);
4794
4795 IPADBG("ip4_flt_hash=%u ip4_flt_nonhash=%u\n",
4796 ipa3_ctx->ip4_flt_tbl_hash_lcl,
4797 ipa3_ctx->ip4_flt_tbl_nhash_lcl);
4798
4799 IPADBG("ip6_flt_hash=%u ip6_flt_nonhash=%u\n",
4800 ipa3_ctx->ip6_flt_tbl_hash_lcl,
4801 ipa3_ctx->ip6_flt_tbl_nhash_lcl);
4802
4803 if (ipa3_ctx->smem_reqd_sz > ipa3_ctx->smem_sz) {
4804 IPAERR("SW expect more core memory, needed %d, avail %d\n",
4805 ipa3_ctx->smem_reqd_sz, ipa3_ctx->smem_sz);
4806 result = -ENOMEM;
4807 goto fail_init_hw;
4808 }
4809
4810 result = ipa3_allocate_dma_task_for_gsi();
4811 if (result) {
4812 IPAERR("failed to allocate dma task\n");
4813 goto fail_dma_task;
4814 }
4815
4816 if (ipa3_nat_ipv6ct_init_devices()) {
4817 IPAERR("unable to init NAT and IPv6CT devices\n");
4818 result = -ENODEV;
4819 goto fail_nat_ipv6ct_init_dev;
4820 }
4821
4822 result = ipa3_alloc_pkt_init();
4823 if (result) {
4824 IPAERR("Failed to alloc pkt_init payload\n");
4825 result = -ENODEV;
4826 goto fail_allok_pkt_init;
4827 }
4828
4829 if (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5)
4830 ipa3_enable_dcd();
4831
Amir Levy54fe4d32017-03-16 11:21:49 +02004832 /*
4833 * indication whether working in MHI config or non MHI config is given
4834 * in ipa3_write which is launched before ipa3_post_init. i.e. from
4835 * this point it is safe to use ipa3_ep_mapping array and the correct
4836 * entry will be returned from ipa3_get_hw_type_index()
4837 */
4838 ipa_init_ep_flt_bitmap();
4839 IPADBG("EP with flt support bitmap 0x%x (%u pipes)\n",
4840 ipa3_ctx->ep_flt_bitmap, ipa3_ctx->ep_flt_num);
4841
4842 /* Assign resource limitation to each group */
4843 ipa3_set_resorce_groups_min_max_limits();
4844
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004845 idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
4846 idr_init(idr);
4847 idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
4848 idr_init(idr);
4849
Amir Levy54fe4d32017-03-16 11:21:49 +02004850 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4851 if (!ipa_is_ep_support_flt(i))
4852 continue;
4853
4854 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
4855 INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
4856 flt_tbl->in_sys[IPA_RULE_HASHABLE] =
4857 !ipa3_ctx->ip4_flt_tbl_hash_lcl;
4858 flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
4859 !ipa3_ctx->ip4_flt_tbl_nhash_lcl;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004860 flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v4];
Amir Levy54fe4d32017-03-16 11:21:49 +02004861
4862 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
4863 INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
4864 flt_tbl->in_sys[IPA_RULE_HASHABLE] =
4865 !ipa3_ctx->ip6_flt_tbl_hash_lcl;
4866 flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
4867 !ipa3_ctx->ip6_flt_tbl_nhash_lcl;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004868 flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v6];
Amir Levy54fe4d32017-03-16 11:21:49 +02004869 }
4870
4871 if (!ipa3_ctx->apply_rg10_wa) {
4872 result = ipa3_init_interrupts();
4873 if (result) {
4874 IPAERR("ipa initialization of interrupts failed\n");
4875 result = -ENODEV;
4876 goto fail_register_device;
4877 }
4878 } else {
4879 IPADBG("Initialization of ipa interrupts skipped\n");
4880 }
Amir Levy9659e592016-10-27 18:08:27 +03004881
Amir Levy3afd94a2017-01-05 10:19:13 +02004882 /*
Amir Levy5cfbb322017-01-09 14:53:02 +02004883 * IPAv3.5 and above requires to disable prefetch for USB in order
Skylar Chang84099692018-04-24 14:43:03 -07004884 * to allow MBIM to work.
Amir Levy3afd94a2017-01-05 10:19:13 +02004885 */
Michael Adisumartad68ab112017-06-14 11:40:06 -07004886 if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5
4887 && ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) &&
Amir Levy5cfbb322017-01-09 14:53:02 +02004888 (!ipa3_ctx->ipa_config_is_mhi))
Amir Levy3afd94a2017-01-05 10:19:13 +02004889 ipa3_disable_prefetch(IPA_CLIENT_USB_CONS);
4890
Skylar Chang84099692018-04-24 14:43:03 -07004891 if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5
4892 && ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) &&
4893 (ipa3_ctx->ipa_config_is_mhi))
4894 ipa3_disable_prefetch(IPA_CLIENT_MHI_CONS);
4895
Amir Levya59ed3f2017-03-05 17:30:55 +02004896 memset(&gsi_props, 0, sizeof(gsi_props));
4897 gsi_props.ver = ipa3_get_gsi_ver(resource_p->ipa_hw_type);
4898 gsi_props.ee = resource_p->ee;
4899 gsi_props.intr = GSI_INTR_IRQ;
Amir Levya59ed3f2017-03-05 17:30:55 +02004900 gsi_props.phys_addr = resource_p->transport_mem_base;
4901 gsi_props.size = resource_p->transport_mem_size;
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04004902 if (ipa3_ctx->ipa3_hw_mode == IPA_HW_MODE_EMULATION) {
4903 gsi_props.irq = resource_p->emulator_irq;
4904 gsi_props.emulator_intcntrlr_client_isr = ipa3_get_isr();
4905 gsi_props.emulator_intcntrlr_addr =
4906 resource_p->emulator_intcntrlr_mem_base;
4907 gsi_props.emulator_intcntrlr_size =
4908 resource_p->emulator_intcntrlr_mem_size;
4909 } else {
4910 gsi_props.irq = resource_p->transport_irq;
4911 }
Amir Levya59ed3f2017-03-05 17:30:55 +02004912 gsi_props.notify_cb = ipa_gsi_notify_cb;
4913 gsi_props.req_clk_cb = NULL;
4914 gsi_props.rel_clk_cb = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004915
Ghanim Fodic823bc62017-10-21 17:29:53 +03004916 if (ipa3_ctx->ipa_config_is_mhi) {
4917 gsi_props.mhi_er_id_limits_valid = true;
4918 gsi_props.mhi_er_id_limits[0] = resource_p->mhi_evid_limits[0];
4919 gsi_props.mhi_er_id_limits[1] = resource_p->mhi_evid_limits[1];
4920 }
4921
Amir Levya59ed3f2017-03-05 17:30:55 +02004922 result = gsi_register_device(&gsi_props,
4923 &ipa3_ctx->gsi_dev_hdl);
4924 if (result != GSI_STATUS_SUCCESS) {
4925 IPAERR(":gsi register error - %d\n", result);
4926 result = -ENODEV;
4927 goto fail_register_device;
Amir Levy9659e592016-10-27 18:08:27 +03004928 }
Amir Levya59ed3f2017-03-05 17:30:55 +02004929 IPADBG("IPA gsi is registered\n");
Amir Levy9659e592016-10-27 18:08:27 +03004930
4931 /* setup the AP-IPA pipes */
4932 if (ipa3_setup_apps_pipes()) {
4933 IPAERR(":failed to setup IPA-Apps pipes\n");
4934 result = -ENODEV;
4935 goto fail_setup_apps_pipes;
4936 }
Amir Levya59ed3f2017-03-05 17:30:55 +02004937 IPADBG("IPA GPI pipes were connected\n");
Amir Levy9659e592016-10-27 18:08:27 +03004938
4939 if (ipa3_ctx->use_ipa_teth_bridge) {
4940 /* Initialize the tethering bridge driver */
4941 result = ipa3_teth_bridge_driver_init();
4942 if (result) {
4943 IPAERR(":teth_bridge init failed (%d)\n", -result);
4944 result = -ENODEV;
4945 goto fail_teth_bridge_driver_init;
4946 }
4947 IPADBG("teth_bridge initialized");
4948 }
4949
Amir Levy9659e592016-10-27 18:08:27 +03004950 result = ipa3_uc_interface_init();
4951 if (result)
4952 IPAERR(":ipa Uc interface init failed (%d)\n", -result);
4953 else
4954 IPADBG(":ipa Uc interface init ok\n");
4955
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004956 uc_hdlrs.ipa_uc_loaded_hdlr = ipa3_uc_is_loaded;
4957 ipa3_uc_register_handlers(IPA_HW_FEATURE_COMMON, &uc_hdlrs);
4958
Amir Levy9659e592016-10-27 18:08:27 +03004959 result = ipa3_wdi_init();
4960 if (result)
4961 IPAERR(":wdi init failed (%d)\n", -result);
4962 else
4963 IPADBG(":wdi init ok\n");
4964
4965 result = ipa3_ntn_init();
4966 if (result)
4967 IPAERR(":ntn init failed (%d)\n", -result);
4968 else
4969 IPADBG(":ntn init ok\n");
4970
Skylar Chang6f6e3072017-07-28 10:03:47 -07004971 result = ipa_hw_stats_init();
4972 if (result)
4973 IPAERR("fail to init stats %d\n", result);
4974 else
4975 IPADBG(":stats init ok\n");
4976
Amir Levy9659e592016-10-27 18:08:27 +03004977 ipa3_register_panic_hdlr();
4978
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04004979 ipa3_debugfs_init();
4980
Amir Levy9659e592016-10-27 18:08:27 +03004981 mutex_lock(&ipa3_ctx->lock);
4982 ipa3_ctx->ipa_initialization_complete = true;
4983 mutex_unlock(&ipa3_ctx->lock);
4984
4985 ipa3_trigger_ipa_ready_cbs();
4986 complete_all(&ipa3_ctx->init_completion_obj);
4987 pr_info("IPA driver initialization was successful.\n");
4988
4989 return 0;
4990
4991fail_teth_bridge_driver_init:
4992 ipa3_teardown_apps_pipes();
4993fail_setup_apps_pipes:
Amir Levya59ed3f2017-03-05 17:30:55 +02004994 gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03004995fail_register_device:
Amir Levy9659e592016-10-27 18:08:27 +03004996 ipa3_destroy_flt_tbl_idrs();
Skylar Changefc0a0f2018-03-29 11:17:40 -07004997fail_allok_pkt_init:
4998 ipa3_nat_ipv6ct_destroy_devices();
4999fail_nat_ipv6ct_init_dev:
5000 ipa3_free_dma_task_for_gsi();
5001fail_dma_task:
5002fail_init_hw:
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005003 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_EMULATION)
5004 ipahal_destroy();
Skylar Changefc0a0f2018-03-29 11:17:40 -07005005fail_ipahal:
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005006 ipa3_proxy_clk_unvote();
Skylar Changefc0a0f2018-03-29 11:17:40 -07005007
Amir Levy9659e592016-10-27 18:08:27 +03005008 return result;
5009}
5010
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005011static int ipa3_manual_load_ipa_fws(void)
Amir Levy9659e592016-10-27 18:08:27 +03005012{
5013 int result;
5014 const struct firmware *fw;
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005015 const char *path = IPA_FWS_PATH;
Amir Levy9659e592016-10-27 18:08:27 +03005016
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005017 if (ipa3_ctx->ipa3_hw_mode == IPA_HW_MODE_EMULATION) {
5018 switch (ipa3_get_emulation_type()) {
5019 case IPA_HW_v3_5_1:
5020 path = IPA_FWS_PATH_3_5_1;
5021 break;
5022 case IPA_HW_v4_0:
5023 path = IPA_FWS_PATH_4_0;
5024 break;
5025 default:
5026 break;
5027 }
5028 }
Amir Levy9659e592016-10-27 18:08:27 +03005029
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005030 IPADBG("Manual FW loading (%s) process initiated\n", path);
5031
5032 result = request_firmware(&fw, path, ipa3_ctx->cdev.dev);
Amir Levy9659e592016-10-27 18:08:27 +03005033 if (result < 0) {
5034 IPAERR("request_firmware failed, error %d\n", result);
5035 return result;
5036 }
5037 if (fw == NULL) {
5038 IPAERR("Firmware is NULL!\n");
5039 return -EINVAL;
5040 }
5041
5042 IPADBG("FWs are available for loading\n");
5043
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005044 if (ipa3_ctx->ipa3_hw_mode == IPA_HW_MODE_EMULATION) {
5045 result = emulator_load_fws(fw,
5046 ipa3_res.transport_mem_base,
5047 ipa3_res.transport_mem_size);
5048 } else {
5049 result = ipa3_load_fws(fw, ipa3_res.transport_mem_base);
5050 }
Amir Levy9659e592016-10-27 18:08:27 +03005051 if (result) {
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005052 IPAERR("Manual IPA FWs loading has failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03005053 release_firmware(fw);
5054 return result;
5055 }
5056
5057 result = gsi_enable_fw(ipa3_res.transport_mem_base,
Amir Levy85dcd172016-12-06 17:47:39 +02005058 ipa3_res.transport_mem_size,
5059 ipa3_get_gsi_ver(ipa3_res.ipa_hw_type));
Amir Levy9659e592016-10-27 18:08:27 +03005060 if (result) {
5061 IPAERR("Failed to enable GSI FW\n");
5062 release_firmware(fw);
5063 return result;
5064 }
5065
5066 release_firmware(fw);
5067
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005068 IPADBG("Manual FW loading process is complete\n");
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005069
Amir Levy9659e592016-10-27 18:08:27 +03005070 return 0;
5071}
5072
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005073static int ipa3_pil_load_ipa_fws(void)
Amir Levy9659e592016-10-27 18:08:27 +03005074{
5075 void *subsystem_get_retval = NULL;
5076
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005077 IPADBG("PIL FW loading process initiated\n");
Amir Levy9659e592016-10-27 18:08:27 +03005078
5079 subsystem_get_retval = subsystem_get(IPA_SUBSYSTEM_NAME);
5080 if (IS_ERR_OR_NULL(subsystem_get_retval)) {
5081 IPAERR("Unable to trigger PIL process for FW loading\n");
5082 return -EINVAL;
5083 }
5084
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005085 IPADBG("PIL FW loading process is complete\n");
Amir Levy9659e592016-10-27 18:08:27 +03005086 return 0;
5087}
5088
Ghanim Fodia5f376a2017-10-17 18:14:53 +03005089static void ipa3_load_ipa_fw(struct work_struct *work)
5090{
5091 int result;
5092
5093 IPADBG("Entry\n");
5094
Skylar Changefc0a0f2018-03-29 11:17:40 -07005095 result = ipa3_attach_to_smmu();
5096 if (result) {
5097 IPAERR("IPA attach to smmu failed %d\n", result);
5098 return;
5099 }
5100
Ghanim Fodia5f376a2017-10-17 18:14:53 +03005101 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
5102
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005103 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_EMULATION &&
5104 (ipa3_is_msm_device() || (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5)))
Ghanim Fodia5f376a2017-10-17 18:14:53 +03005105 result = ipa3_pil_load_ipa_fws();
5106 else
5107 result = ipa3_manual_load_ipa_fws();
5108
5109 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
5110
5111 if (result) {
5112 IPAERR("IPA FW loading process has failed\n");
5113 return;
5114 }
5115 pr_info("IPA FW loaded successfully\n");
5116
Skylar Changefc0a0f2018-03-29 11:17:40 -07005117 result = ipa3_post_init(&ipa3_res, ipa3_ctx->cdev.dev);
Ghanim Fodia5f376a2017-10-17 18:14:53 +03005118 if (result)
5119 IPAERR("IPA post init failed %d\n", result);
5120}
5121
Amir Levy9659e592016-10-27 18:08:27 +03005122static ssize_t ipa3_write(struct file *file, const char __user *buf,
5123 size_t count, loff_t *ppos)
5124{
5125 unsigned long missing;
Amir Levy9659e592016-10-27 18:08:27 +03005126
Amir Levy2da9d452017-12-12 10:09:46 +02005127 char dbg_buff[32] = { 0 };
Amir Levy9659e592016-10-27 18:08:27 +03005128
5129 if (sizeof(dbg_buff) < count + 1)
5130 return -EFAULT;
5131
5132 missing = copy_from_user(dbg_buff, buf, count);
5133
5134 if (missing) {
5135 IPAERR("Unable to copy data from user\n");
5136 return -EFAULT;
5137 }
5138
Amir Levya5774c42017-12-14 22:15:54 +02005139 dbg_buff[count] = '\0';
Mohammed Javidbf4c8022017-08-07 23:15:48 +05305140
Amir Levy2da9d452017-12-12 10:09:46 +02005141 IPADBG("user input string %s\n", dbg_buff);
5142
Amir Levy9659e592016-10-27 18:08:27 +03005143 /* Prevent consequent calls from trying to load the FW again. */
5144 if (ipa3_is_ready())
5145 return count;
5146
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005147 /* Check MHI configuration on MDM devices */
5148 if (!ipa3_is_msm_device()) {
Amir Levy2da9d452017-12-12 10:09:46 +02005149
5150 if (strnstr(dbg_buff, "vlan", strlen(dbg_buff))) {
5151 if (strnstr(dbg_buff, "eth", strlen(dbg_buff)))
5152 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_EMAC] =
5153 true;
5154 if (strnstr(dbg_buff, "rndis", strlen(dbg_buff)))
5155 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_RNDIS] =
5156 true;
5157 if (strnstr(dbg_buff, "ecm", strlen(dbg_buff)))
5158 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM] =
5159 true;
5160
5161 /*
5162 * when vlan mode is passed to our dev we expect
5163 * another write
5164 */
5165 return count;
5166 }
5167
Amir Levya5774c42017-12-14 22:15:54 +02005168 /* trim ending newline character if any */
5169 if (count && (dbg_buff[count - 1] == '\n'))
5170 dbg_buff[count - 1] = '\0';
5171
Amir Levy54fe4d32017-03-16 11:21:49 +02005172 if (!strcasecmp(dbg_buff, "MHI")) {
5173 ipa3_ctx->ipa_config_is_mhi = true;
5174 pr_info(
Amir Levy2da9d452017-12-12 10:09:46 +02005175 "IPA is loading with MHI configuration\n");
Amir Levya5774c42017-12-14 22:15:54 +02005176 } else if (!strcmp(dbg_buff, "1")) {
Amir Levy54fe4d32017-03-16 11:21:49 +02005177 pr_info(
Amir Levy2da9d452017-12-12 10:09:46 +02005178 "IPA is loading with non MHI configuration\n");
5179 } else {
5180 IPAERR("got invalid string %s not loading FW\n",
5181 dbg_buff);
5182 return count;
Amir Levy54fe4d32017-03-16 11:21:49 +02005183 }
Amir Levy54fe4d32017-03-16 11:21:49 +02005184 }
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005185
Skylar Changafc22fe2019-04-25 14:10:52 -07005186 /* Prevent multiple calls from trying to load the FW again. */
5187 if (ipa3_ctx->fw_loaded) {
5188 IPAERR("not load FW again\n");
5189 return count;
5190 }
5191
5192 /* Schedule WQ to load ipa-fws */
5193 ipa3_ctx->fw_loaded = true;
5194
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005195 queue_work(ipa3_ctx->transport_power_mgmt_wq,
Ghanim Fodia5f376a2017-10-17 18:14:53 +03005196 &ipa3_fw_loading_work);
Ghanim Fodi03dcc272017-08-08 18:13:25 +03005197
Ghanim Fodia5f376a2017-10-17 18:14:53 +03005198 IPADBG("Scheduled a work to load IPA FW\n");
Amir Levy9659e592016-10-27 18:08:27 +03005199 return count;
5200}
5201
Skylar Chang48afa052017-10-25 09:32:57 -07005202/**
5203 * ipa3_tz_unlock_reg - Unlocks memory regions so that they become accessible
5204 * from AP.
5205 * @reg_info - Pointer to array of memory regions to unlock
5206 * @num_regs - Number of elements in the array
5207 *
5208 * Converts the input array of regions to a struct that TZ understands and
5209 * issues an SCM call.
5210 * Also flushes the memory cache to DDR in order to make sure that TZ sees the
5211 * correct data structure.
5212 *
5213 * Returns: 0 on success, negative on failure
5214 */
5215int ipa3_tz_unlock_reg(struct ipa_tz_unlock_reg_info *reg_info, u16 num_regs)
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005216{
5217 int i, size, ret, resp;
5218 struct tz_smmu_ipa_protect_region_iovec_s *ipa_tz_unlock_vec;
5219 struct tz_smmu_ipa_protect_region_s cmd_buf;
Skylar Chang3a696ba2017-10-25 09:35:07 -07005220 struct scm_desc desc = {0};
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005221
Skylar Chang48afa052017-10-25 09:32:57 -07005222 if (reg_info == NULL || num_regs == 0) {
5223 IPAERR("Bad parameters\n");
5224 return -EFAULT;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005225 }
Skylar Chang48afa052017-10-25 09:32:57 -07005226
5227 size = num_regs * sizeof(struct tz_smmu_ipa_protect_region_iovec_s);
5228 ipa_tz_unlock_vec = kzalloc(PAGE_ALIGN(size), GFP_KERNEL);
5229 if (ipa_tz_unlock_vec == NULL)
5230 return -ENOMEM;
5231
5232 for (i = 0; i < num_regs; i++) {
5233 ipa_tz_unlock_vec[i].input_addr = reg_info[i].reg_addr ^
5234 (reg_info[i].reg_addr & 0xFFF);
5235 ipa_tz_unlock_vec[i].output_addr = reg_info[i].reg_addr ^
5236 (reg_info[i].reg_addr & 0xFFF);
5237 ipa_tz_unlock_vec[i].size = reg_info[i].size;
5238 ipa_tz_unlock_vec[i].attr = IPA_TZ_UNLOCK_ATTRIBUTE;
5239 }
5240
5241 /* pass physical address of command buffer */
5242 cmd_buf.iovec_buf = virt_to_phys((void *)ipa_tz_unlock_vec);
5243 cmd_buf.size_bytes = size;
5244
5245 /* flush cache to DDR */
5246 __cpuc_flush_dcache_area((void *)ipa_tz_unlock_vec, size);
5247 outer_flush_range(cmd_buf.iovec_buf, cmd_buf.iovec_buf + size);
Skylar Chang3a696ba2017-10-25 09:35:07 -07005248 if (!is_scm_armv8())
5249 ret = scm_call(SCM_SVC_MP, TZ_MEM_PROTECT_REGION_ID,
5250 &cmd_buf, sizeof(cmd_buf), &resp, sizeof(resp));
5251 else {
5252 desc.args[0] = virt_to_phys((void *)ipa_tz_unlock_vec);
5253 desc.args[1] = size;
5254 desc.arginfo = SCM_ARGS(2, SCM_RO, SCM_VAL);
5255 ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
5256 TZ_MEM_PROTECT_REGION_ID), &desc);
5257 }
Skylar Chang48afa052017-10-25 09:32:57 -07005258
Skylar Chang48afa052017-10-25 09:32:57 -07005259 if (ret) {
5260 IPAERR("scm call SCM_SVC_MP failed: %d\n", ret);
5261 kfree(ipa_tz_unlock_vec);
5262 return -EFAULT;
5263 }
5264 kfree(ipa_tz_unlock_vec);
5265
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005266 return 0;
5267}
5268
Skylar Changcd3902d2017-03-27 18:08:27 -07005269static int ipa3_alloc_pkt_init(void)
5270{
5271 struct ipa_mem_buffer mem;
5272 struct ipahal_imm_cmd_pyld *cmd_pyld;
5273 struct ipahal_imm_cmd_ip_packet_init cmd = {0};
5274 int i;
5275
5276 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
5277 &cmd, false);
5278 if (!cmd_pyld) {
5279 IPAERR("failed to construct IMM cmd\n");
5280 return -ENOMEM;
5281 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -07005282 ipa3_ctx->pkt_init_imm_opcode = cmd_pyld->opcode;
Skylar Changcd3902d2017-03-27 18:08:27 -07005283
5284 mem.size = cmd_pyld->len * ipa3_ctx->ipa_num_pipes;
5285 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
5286 &mem.phys_base, GFP_KERNEL);
5287 if (!mem.base) {
5288 IPAERR("failed to alloc DMA buff of size %d\n", mem.size);
5289 ipahal_destroy_imm_cmd(cmd_pyld);
5290 return -ENOMEM;
5291 }
5292 ipahal_destroy_imm_cmd(cmd_pyld);
5293
5294 memset(mem.base, 0, mem.size);
5295 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
5296 cmd.destination_pipe_index = i;
5297 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
5298 &cmd, false);
5299 if (!cmd_pyld) {
5300 IPAERR("failed to construct IMM cmd\n");
5301 dma_free_coherent(ipa3_ctx->pdev,
5302 mem.size,
5303 mem.base,
5304 mem.phys_base);
5305 return -ENOMEM;
5306 }
5307 memcpy(mem.base + i * cmd_pyld->len, cmd_pyld->data,
5308 cmd_pyld->len);
5309 ipa3_ctx->pkt_init_imm[i] = mem.phys_base + i * cmd_pyld->len;
5310 ipahal_destroy_imm_cmd(cmd_pyld);
5311 }
5312
5313 return 0;
5314}
5315
Amir Levy9659e592016-10-27 18:08:27 +03005316/**
Skylar Chang68c37d82018-04-07 16:42:36 -07005317 * ipa3_pre_init() - Initialize the IPA Driver.
5318 * This part contains all initialization which doesn't require IPA HW, such
5319 * as structure allocations and initializations, register writes, etc.
5320 *
5321 * @resource_p: contain platform specific values from DST file
5322 * @pdev: The platform device structure representing the IPA driver
5323 *
5324 * Function initialization process:
5325 * Allocate memory for the driver context data struct
5326 * Initializing the ipa3_ctx with :
5327 * 1)parsed values from the dts file
5328 * 2)parameters passed to the module initialization
5329 * 3)read HW values(such as core memory size)
5330 * Map IPA core registers to CPU memory
5331 * Restart IPA core(HW reset)
5332 * Initialize the look-aside caches(kmem_cache/slab) for filter,
5333 * routing and IPA-tree
5334 * Create memory pool with 4 objects for DMA operations(each object
5335 * is 512Bytes long), this object will be use for tx(A5->IPA)
5336 * Initialize lists head(routing, hdr, system pipes)
5337 * Initialize mutexes (for ipa_ctx and NAT memory mutexes)
5338 * Initialize spinlocks (for list related to A5<->IPA pipes)
5339 * Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq"
5340 * Initialize Red-Black-Tree(s) for handles of header,routing rule,
5341 * routing table ,filtering rule
5342 * Initialize the filter block by committing IPV4 and IPV6 default rules
5343 * Create empty routing table in system memory(no committing)
5344 * Create a char-device for IPA
5345 * Initialize IPA RM (resource manager)
5346 * Configure GSI registers (in GSI case)
5347 */
Amir Levy9659e592016-10-27 18:08:27 +03005348static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
Skylar Changefc0a0f2018-03-29 11:17:40 -07005349 struct platform_device *ipa_pdev)
Amir Levy9659e592016-10-27 18:08:27 +03005350{
5351 int result = 0;
5352 int i;
Amir Levy9659e592016-10-27 18:08:27 +03005353 struct ipa3_rt_tbl_set *rset;
Mohammed Javidc6db3362018-02-13 13:41:38 +05305354 struct ipa_active_client_logging_info log_info;
Skylar Changefc0a0f2018-03-29 11:17:40 -07005355 struct cdev *cdev;
Amir Levy9659e592016-10-27 18:08:27 +03005356
5357 IPADBG("IPA Driver initialization started\n");
5358
5359 ipa3_ctx = kzalloc(sizeof(*ipa3_ctx), GFP_KERNEL);
5360 if (!ipa3_ctx) {
5361 IPAERR(":kzalloc err.\n");
5362 result = -ENOMEM;
5363 goto fail_mem_ctx;
5364 }
5365
5366 ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0);
Skylar Chang841c1452017-04-03 16:07:22 -07005367 if (ipa3_ctx->logbuf == NULL)
Mohammed Javid0af3c662018-06-29 15:06:00 +05305368 IPADBG("failed to create IPC log, continue...\n");
Amir Levy9659e592016-10-27 18:08:27 +03005369
Skylar Changefc0a0f2018-03-29 11:17:40 -07005370 /* ipa3_ctx->pdev and ipa3_ctx->uc_pdev will be set in the smmu probes*/
5371 ipa3_ctx->master_pdev = ipa_pdev;
Michael Adisumartac8c404a2018-04-05 18:01:45 -07005372 for (i = 0; i < IPA_SMMU_CB_MAX; i++)
5373 ipa3_ctx->s1_bypass_arr[i] = true;
Michael Adisumarta93e97522017-10-06 15:49:46 -07005374
Amir Levy9659e592016-10-27 18:08:27 +03005375 ipa3_ctx->ipa_wrapper_base = resource_p->ipa_mem_base;
5376 ipa3_ctx->ipa_wrapper_size = resource_p->ipa_mem_size;
5377 ipa3_ctx->ipa_hw_type = resource_p->ipa_hw_type;
5378 ipa3_ctx->ipa3_hw_mode = resource_p->ipa3_hw_mode;
5379 ipa3_ctx->use_ipa_teth_bridge = resource_p->use_ipa_teth_bridge;
Amir Levy9659e592016-10-27 18:08:27 +03005380 ipa3_ctx->modem_cfg_emb_pipe_flt = resource_p->modem_cfg_emb_pipe_flt;
5381 ipa3_ctx->ipa_wdi2 = resource_p->ipa_wdi2;
Mohammed Javid80d0e2a2019-06-10 14:11:42 +05305382 ipa3_ctx->ipa_config_is_auto = resource_p->ipa_config_is_auto;
Amir Levy9659e592016-10-27 18:08:27 +03005383 ipa3_ctx->use_64_bit_dma_mask = resource_p->use_64_bit_dma_mask;
5384 ipa3_ctx->wan_rx_ring_size = resource_p->wan_rx_ring_size;
5385 ipa3_ctx->lan_rx_ring_size = resource_p->lan_rx_ring_size;
5386 ipa3_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
5387 ipa3_ctx->tethered_flow_control = resource_p->tethered_flow_control;
Amir Levy9659e592016-10-27 18:08:27 +03005388 ipa3_ctx->ee = resource_p->ee;
5389 ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa;
5390 ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa;
Michael Adisumarta3e350812017-09-18 14:54:36 -07005391 ipa3_ctx->use_ipa_pm = resource_p->use_ipa_pm;
Mohammed Javid03854df2018-06-20 18:36:57 +05305392 ipa3_ctx->wdi_over_pcie = resource_p->wdi_over_pcie;
Amir Levy9659e592016-10-27 18:08:27 +03005393 ipa3_ctx->ipa3_active_clients_logging.log_rdy = false;
Mohammed Javid73cd4d22018-04-03 17:15:49 +05305394 ipa3_ctx->ipa_config_is_mhi = resource_p->ipa_mhi_dynamic_config;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005395 ipa3_ctx->mhi_evid_limits[0] = resource_p->mhi_evid_limits[0];
5396 ipa3_ctx->mhi_evid_limits[1] = resource_p->mhi_evid_limits[1];
Skylar Changefc0a0f2018-03-29 11:17:40 -07005397
5398 WARN(ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL,
5399 "Non NORMAL IPA HW mode, is this emulation platform ?");
5400
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005401 if (resource_p->ipa_tz_unlock_reg) {
5402 ipa3_ctx->ipa_tz_unlock_reg_num =
5403 resource_p->ipa_tz_unlock_reg_num;
5404 ipa3_ctx->ipa_tz_unlock_reg = kcalloc(
5405 ipa3_ctx->ipa_tz_unlock_reg_num,
5406 sizeof(*ipa3_ctx->ipa_tz_unlock_reg),
5407 GFP_KERNEL);
5408 if (ipa3_ctx->ipa_tz_unlock_reg == NULL) {
5409 result = -ENOMEM;
5410 goto fail_tz_unlock_reg;
5411 }
5412 for (i = 0; i < ipa3_ctx->ipa_tz_unlock_reg_num; i++) {
5413 ipa3_ctx->ipa_tz_unlock_reg[i].reg_addr =
5414 resource_p->ipa_tz_unlock_reg[i].reg_addr;
5415 ipa3_ctx->ipa_tz_unlock_reg[i].size =
5416 resource_p->ipa_tz_unlock_reg[i].size;
5417 }
5418 }
5419
5420 /* unlock registers for uc */
Skylar Chang48afa052017-10-25 09:32:57 -07005421 result = ipa3_tz_unlock_reg(ipa3_ctx->ipa_tz_unlock_reg,
5422 ipa3_ctx->ipa_tz_unlock_reg_num);
5423 if (result)
5424 IPAERR("Failed to unlock memory region using TZ\n");
Amir Levy9659e592016-10-27 18:08:27 +03005425
5426 /* default aggregation parameters */
5427 ipa3_ctx->aggregation_type = IPA_MBIM_16;
5428 ipa3_ctx->aggregation_byte_limit = 1;
5429 ipa3_ctx->aggregation_time_limit = 0;
5430
5431 ipa3_ctx->ctrl = kzalloc(sizeof(*ipa3_ctx->ctrl), GFP_KERNEL);
5432 if (!ipa3_ctx->ctrl) {
5433 IPAERR("memory allocation error for ctrl\n");
5434 result = -ENOMEM;
5435 goto fail_mem_ctrl;
5436 }
5437 result = ipa3_controller_static_bind(ipa3_ctx->ctrl,
5438 ipa3_ctx->ipa_hw_type);
5439 if (result) {
5440 IPAERR("fail to static bind IPA ctrl.\n");
5441 result = -EFAULT;
5442 goto fail_bind;
5443 }
5444
Skylar Changefc0a0f2018-03-29 11:17:40 -07005445 result = ipa3_init_mem_partition(ipa3_ctx->master_pdev->dev.of_node);
Amir Levy9659e592016-10-27 18:08:27 +03005446 if (result) {
5447 IPAERR(":ipa3_init_mem_partition failed!\n");
5448 result = -ENODEV;
5449 goto fail_init_mem_partition;
5450 }
5451
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005452 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_VIRTUAL &&
5453 ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_EMULATION) {
Skylar Changefc0a0f2018-03-29 11:17:40 -07005454 ipa3_ctx->ctrl->msm_bus_data_ptr =
5455 msm_bus_cl_get_pdata(ipa3_ctx->master_pdev);
5456 if (ipa3_ctx->ctrl->msm_bus_data_ptr == NULL) {
5457 IPAERR("failed to get bus scaling\n");
5458 goto fail_bus_reg;
5459 }
Ghanim Fodi6a831342017-03-07 18:19:15 +02005460 IPADBG("Use bus scaling info from device tree #usecases=%d\n",
Skylar Changefc0a0f2018-03-29 11:17:40 -07005461 ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases);
Amir Levy9659e592016-10-27 18:08:27 +03005462
Skylar Changefc0a0f2018-03-29 11:17:40 -07005463 /* get BUS handle */
5464 ipa3_ctx->ipa_bus_hdl =
5465 msm_bus_scale_register_client(
5466 ipa3_ctx->ctrl->msm_bus_data_ptr);
5467 if (!ipa3_ctx->ipa_bus_hdl) {
5468 IPAERR("fail to register with bus mgr!\n");
5469 result = -ENODEV;
5470 goto fail_bus_reg;
5471 }
Amir Levy9659e592016-10-27 18:08:27 +03005472 }
5473
5474 /* get IPA clocks */
Skylar Changefc0a0f2018-03-29 11:17:40 -07005475 result = ipa3_get_clks(&ipa3_ctx->master_pdev->dev);
Amir Levy9659e592016-10-27 18:08:27 +03005476 if (result)
5477 goto fail_clk;
5478
5479 /* init active_clients_log after getting ipa-clk */
Ghanim Fodic48ba992017-12-24 19:28:38 +02005480 result = ipa3_active_clients_log_init();
5481 if (result)
Amir Levy9659e592016-10-27 18:08:27 +03005482 goto fail_init_active_client;
5483
5484 /* Enable ipa3_ctx->enable_clock_scaling */
5485 ipa3_ctx->enable_clock_scaling = 1;
5486 ipa3_ctx->curr_ipa_clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
5487
5488 /* enable IPA clocks explicitly to allow the initialization */
5489 ipa3_enable_clks();
5490
5491 /* setup IPA register access */
5492 IPADBG("Mapping 0x%x\n", resource_p->ipa_mem_base +
5493 ipa3_ctx->ctrl->ipa_reg_base_ofst);
5494 ipa3_ctx->mmio = ioremap(resource_p->ipa_mem_base +
5495 ipa3_ctx->ctrl->ipa_reg_base_ofst,
5496 resource_p->ipa_mem_size);
5497 if (!ipa3_ctx->mmio) {
5498 IPAERR(":ipa-base ioremap err.\n");
5499 result = -EFAULT;
5500 goto fail_remap;
5501 }
5502
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005503 IPADBG(
5504 "base(0x%x)+offset(0x%x)=(0x%x) mapped to (%pK) with len (0x%x)\n",
5505 resource_p->ipa_mem_base,
5506 ipa3_ctx->ctrl->ipa_reg_base_ofst,
5507 resource_p->ipa_mem_base + ipa3_ctx->ctrl->ipa_reg_base_ofst,
5508 ipa3_ctx->mmio,
5509 resource_p->ipa_mem_size);
5510
5511 /*
5512 * Emulation requires ipahal be initialized early...for FW
5513 * download, hence...
5514 */
5515 if (ipa3_ctx->ipa3_hw_mode == IPA_HW_MODE_EMULATION) {
5516 if (ipahal_init(ipa3_ctx->ipa_hw_type,
5517 ipa3_ctx->mmio,
5518 &(ipa3_ctx->master_pdev->dev))) {
5519 IPAERR("fail to init ipahal\n");
5520 result = -EFAULT;
5521 goto fail_ipahal_init;
5522 }
5523 }
5524
Amir Levy9659e592016-10-27 18:08:27 +03005525 mutex_init(&ipa3_ctx->ipa3_active_clients.mutex);
Mohammed Javidc6db3362018-02-13 13:41:38 +05305526
5527 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE");
5528 ipa3_active_clients_log_inc(&log_info, false);
5529 ipa3_ctx->q6_proxy_clk_vote_valid = true;
5530 ipa3_ctx->q6_proxy_clk_vote_cnt = 1;
5531
5532 /*Updating the proxy vote cnt 1 */
Skylar Chang242952b2017-07-20 15:04:05 -07005533 atomic_set(&ipa3_ctx->ipa3_active_clients.cnt, 1);
Amir Levy9659e592016-10-27 18:08:27 +03005534
Amir Levy9659e592016-10-27 18:08:27 +03005535 /* Create workqueues for power management */
5536 ipa3_ctx->power_mgmt_wq =
5537 create_singlethread_workqueue("ipa_power_mgmt");
5538 if (!ipa3_ctx->power_mgmt_wq) {
5539 IPAERR("failed to create power mgmt wq\n");
5540 result = -ENOMEM;
5541 goto fail_init_hw;
5542 }
5543
5544 ipa3_ctx->transport_power_mgmt_wq =
5545 create_singlethread_workqueue("transport_power_mgmt");
5546 if (!ipa3_ctx->transport_power_mgmt_wq) {
5547 IPAERR("failed to create transport power mgmt wq\n");
5548 result = -ENOMEM;
5549 goto fail_create_transport_wq;
5550 }
5551
Sridhar Ancha99b505b2016-04-21 23:11:10 +05305552 mutex_init(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03005553
5554 /* init the lookaside cache */
5555 ipa3_ctx->flt_rule_cache = kmem_cache_create("IPA_FLT",
5556 sizeof(struct ipa3_flt_entry), 0, 0, NULL);
5557 if (!ipa3_ctx->flt_rule_cache) {
5558 IPAERR(":ipa flt cache create failed\n");
5559 result = -ENOMEM;
5560 goto fail_flt_rule_cache;
5561 }
5562 ipa3_ctx->rt_rule_cache = kmem_cache_create("IPA_RT",
5563 sizeof(struct ipa3_rt_entry), 0, 0, NULL);
5564 if (!ipa3_ctx->rt_rule_cache) {
5565 IPAERR(":ipa rt cache create failed\n");
5566 result = -ENOMEM;
5567 goto fail_rt_rule_cache;
5568 }
5569 ipa3_ctx->hdr_cache = kmem_cache_create("IPA_HDR",
5570 sizeof(struct ipa3_hdr_entry), 0, 0, NULL);
5571 if (!ipa3_ctx->hdr_cache) {
5572 IPAERR(":ipa hdr cache create failed\n");
5573 result = -ENOMEM;
5574 goto fail_hdr_cache;
5575 }
5576 ipa3_ctx->hdr_offset_cache =
5577 kmem_cache_create("IPA_HDR_OFFSET",
5578 sizeof(struct ipa_hdr_offset_entry), 0, 0, NULL);
5579 if (!ipa3_ctx->hdr_offset_cache) {
5580 IPAERR(":ipa hdr off cache create failed\n");
5581 result = -ENOMEM;
5582 goto fail_hdr_offset_cache;
5583 }
5584 ipa3_ctx->hdr_proc_ctx_cache = kmem_cache_create("IPA_HDR_PROC_CTX",
5585 sizeof(struct ipa3_hdr_proc_ctx_entry), 0, 0, NULL);
5586 if (!ipa3_ctx->hdr_proc_ctx_cache) {
5587 IPAERR(":ipa hdr proc ctx cache create failed\n");
5588 result = -ENOMEM;
5589 goto fail_hdr_proc_ctx_cache;
5590 }
5591 ipa3_ctx->hdr_proc_ctx_offset_cache =
5592 kmem_cache_create("IPA_HDR_PROC_CTX_OFFSET",
5593 sizeof(struct ipa3_hdr_proc_ctx_offset_entry), 0, 0, NULL);
5594 if (!ipa3_ctx->hdr_proc_ctx_offset_cache) {
5595 IPAERR(":ipa hdr proc ctx off cache create failed\n");
5596 result = -ENOMEM;
5597 goto fail_hdr_proc_ctx_offset_cache;
5598 }
5599 ipa3_ctx->rt_tbl_cache = kmem_cache_create("IPA_RT_TBL",
5600 sizeof(struct ipa3_rt_tbl), 0, 0, NULL);
5601 if (!ipa3_ctx->rt_tbl_cache) {
5602 IPAERR(":ipa rt tbl cache create failed\n");
5603 result = -ENOMEM;
5604 goto fail_rt_tbl_cache;
5605 }
5606 ipa3_ctx->tx_pkt_wrapper_cache =
5607 kmem_cache_create("IPA_TX_PKT_WRAPPER",
5608 sizeof(struct ipa3_tx_pkt_wrapper), 0, 0, NULL);
5609 if (!ipa3_ctx->tx_pkt_wrapper_cache) {
5610 IPAERR(":ipa tx pkt wrapper cache create failed\n");
5611 result = -ENOMEM;
5612 goto fail_tx_pkt_wrapper_cache;
5613 }
5614 ipa3_ctx->rx_pkt_wrapper_cache =
5615 kmem_cache_create("IPA_RX_PKT_WRAPPER",
5616 sizeof(struct ipa3_rx_pkt_wrapper), 0, 0, NULL);
5617 if (!ipa3_ctx->rx_pkt_wrapper_cache) {
5618 IPAERR(":ipa rx pkt wrapper cache create failed\n");
5619 result = -ENOMEM;
5620 goto fail_rx_pkt_wrapper_cache;
5621 }
5622
Amir Levy9659e592016-10-27 18:08:27 +03005623 /* init the various list heads */
5624 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_hdr_entry_list);
5625 for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
5626 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_offset_list[i]);
5627 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_free_offset_list[i]);
5628 }
5629 INIT_LIST_HEAD(&ipa3_ctx->hdr_proc_ctx_tbl.head_proc_ctx_entry_list);
5630 for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) {
5631 INIT_LIST_HEAD(&ipa3_ctx->hdr_proc_ctx_tbl.head_offset_list[i]);
5632 INIT_LIST_HEAD(&ipa3_ctx->
5633 hdr_proc_ctx_tbl.head_free_offset_list[i]);
5634 }
5635 INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005636 idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005637 INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005638 idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005639
5640 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
5641 INIT_LIST_HEAD(&rset->head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005642 idr_init(&rset->rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005643 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
5644 INIT_LIST_HEAD(&rset->head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005645 idr_init(&rset->rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005646
5647 INIT_LIST_HEAD(&ipa3_ctx->intf_list);
5648 INIT_LIST_HEAD(&ipa3_ctx->msg_list);
5649 INIT_LIST_HEAD(&ipa3_ctx->pull_msg_list);
5650 init_waitqueue_head(&ipa3_ctx->msg_waitq);
5651 mutex_init(&ipa3_ctx->msg_lock);
5652
Skylar Chang68c37d82018-04-07 16:42:36 -07005653 /* store wlan client-connect-msg-list */
5654 INIT_LIST_HEAD(&ipa3_ctx->msg_wlan_client_list);
5655 mutex_init(&ipa3_ctx->msg_wlan_client_lock);
5656
Amir Levy9659e592016-10-27 18:08:27 +03005657 mutex_init(&ipa3_ctx->lock);
Skylar Changfb792c62017-08-17 12:53:23 -07005658 mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex);
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05305659 mutex_init(&ipa3_ctx->ipa_cne_evt_lock);
Amir Levy9659e592016-10-27 18:08:27 +03005660
5661 idr_init(&ipa3_ctx->ipa_idr);
5662 spin_lock_init(&ipa3_ctx->idr_lock);
5663
5664 /* wlan related member */
5665 memset(&ipa3_ctx->wc_memb, 0, sizeof(ipa3_ctx->wc_memb));
5666 spin_lock_init(&ipa3_ctx->wc_memb.wlan_spinlock);
5667 spin_lock_init(&ipa3_ctx->wc_memb.ipa_tx_mul_spinlock);
5668 INIT_LIST_HEAD(&ipa3_ctx->wc_memb.wlan_comm_desc_list);
5669
Skylar Changefc0a0f2018-03-29 11:17:40 -07005670 ipa3_ctx->cdev.class = class_create(THIS_MODULE, DRV_NAME);
Amir Levy9659e592016-10-27 18:08:27 +03005671
Skylar Changefc0a0f2018-03-29 11:17:40 -07005672 result = alloc_chrdev_region(&ipa3_ctx->cdev.dev_num, 0, 1, DRV_NAME);
Amir Levy9659e592016-10-27 18:08:27 +03005673 if (result) {
5674 IPAERR("alloc_chrdev_region err.\n");
5675 result = -ENODEV;
5676 goto fail_alloc_chrdev_region;
5677 }
5678
Skylar Changefc0a0f2018-03-29 11:17:40 -07005679 ipa3_ctx->cdev.dev = device_create(ipa3_ctx->cdev.class, NULL,
5680 ipa3_ctx->cdev.dev_num, ipa3_ctx, DRV_NAME);
5681 if (IS_ERR(ipa3_ctx->cdev.dev)) {
Amir Levy9659e592016-10-27 18:08:27 +03005682 IPAERR(":device_create err.\n");
5683 result = -ENODEV;
5684 goto fail_device_create;
5685 }
5686
Amir Levy9659e592016-10-27 18:08:27 +03005687 /* Create a wakeup source. */
5688 wakeup_source_init(&ipa3_ctx->w_lock, "IPA_WS");
5689 spin_lock_init(&ipa3_ctx->wakelock_ref_cnt.spinlock);
5690
Michael Adisumarta3e350812017-09-18 14:54:36 -07005691 /* Initialize Power Management framework */
5692 if (ipa3_ctx->use_ipa_pm) {
5693 result = ipa_pm_init(&ipa3_res.pm_init);
5694 if (result) {
5695 IPAERR("IPA PM initialization failed (%d)\n", -result);
5696 result = -ENODEV;
5697 goto fail_ipa_rm_init;
5698 }
5699 IPADBG("IPA resource manager initialized");
5700 } else {
5701 result = ipa_rm_initialize();
5702 if (result) {
5703 IPAERR("RM initialization failed (%d)\n", -result);
5704 result = -ENODEV;
5705 goto fail_ipa_rm_init;
5706 }
5707 IPADBG("IPA resource manager initialized");
Amir Levy9659e592016-10-27 18:08:27 +03005708
Michael Adisumarta3e350812017-09-18 14:54:36 -07005709 result = ipa3_create_apps_resource();
5710 if (result) {
5711 IPAERR("Failed to create APPS_CONS resource\n");
5712 result = -ENODEV;
5713 goto fail_create_apps_resource;
5714 }
Amir Levy9659e592016-10-27 18:08:27 +03005715 }
5716
Amir Levy9659e592016-10-27 18:08:27 +03005717 INIT_LIST_HEAD(&ipa3_ctx->ipa_ready_cb_list);
5718
5719 init_completion(&ipa3_ctx->init_completion_obj);
Skylar Chang0c17c7d2016-10-31 09:57:54 -07005720 init_completion(&ipa3_ctx->uc_loaded_completion_obj);
Amir Levy9659e592016-10-27 18:08:27 +03005721
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005722 result = ipa3_dma_setup();
5723 if (result) {
5724 IPAERR("Failed to setup IPA DMA\n");
5725 result = -ENODEV;
5726 goto fail_ipa_dma_setup;
5727 }
5728
Amir Levy9659e592016-10-27 18:08:27 +03005729 /*
Amir Levya59ed3f2017-03-05 17:30:55 +02005730 * We can't register the GSI driver yet, as it expects
Amir Levy9659e592016-10-27 18:08:27 +03005731 * the GSI FW to be up and running before the registration.
Amir Levya59ed3f2017-03-05 17:30:55 +02005732 *
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005733 * For IPA3.0 and the emulation system, the GSI configuration
5734 * is done by the GSI driver.
5735 *
Amir Levya59ed3f2017-03-05 17:30:55 +02005736 * For IPA3.1 (and on), the GSI configuration is done by TZ.
Amir Levy9659e592016-10-27 18:08:27 +03005737 */
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005738 if (ipa3_ctx->ipa_hw_type == IPA_HW_v3_0 ||
5739 ipa3_ctx->ipa3_hw_mode == IPA_HW_MODE_EMULATION) {
Amir Levya59ed3f2017-03-05 17:30:55 +02005740 result = ipa3_gsi_pre_fw_load_init();
5741 if (result) {
5742 IPAERR("gsi pre FW loading config failed\n");
5743 result = -ENODEV;
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005744 goto fail_gsi_pre_fw_load_init;
Amir Levy9659e592016-10-27 18:08:27 +03005745 }
5746 }
Amir Levy9659e592016-10-27 18:08:27 +03005747
Skylar Changefc0a0f2018-03-29 11:17:40 -07005748 cdev = &ipa3_ctx->cdev.cdev;
5749 cdev_init(cdev, &ipa3_drv_fops);
5750 cdev->owner = THIS_MODULE;
5751 cdev->ops = &ipa3_drv_fops; /* from LDD3 */
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305752
Skylar Changefc0a0f2018-03-29 11:17:40 -07005753 result = cdev_add(cdev, ipa3_ctx->cdev.dev_num, 1);
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305754 if (result) {
5755 IPAERR(":cdev_add err=%d\n", -result);
5756 result = -ENODEV;
5757 goto fail_cdev_add;
5758 }
5759 IPADBG("ipa cdev added successful. major:%d minor:%d\n",
Skylar Changefc0a0f2018-03-29 11:17:40 -07005760 MAJOR(ipa3_ctx->cdev.dev_num),
5761 MINOR(ipa3_ctx->cdev.dev_num));
Mohammed Javidc6db3362018-02-13 13:41:38 +05305762 /*
5763 * for IPA 4.0 offline charge is not needed and we need to prevent
5764 * power collapse until IPA uC is loaded.
5765 */
5766
Skylar Chang40430532017-07-06 14:31:57 -07005767 /* proxy vote for modem is added in ipa3_post_init() phase */
Mohammed Javidc6db3362018-02-13 13:41:38 +05305768 if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0)
5769 ipa3_proxy_clk_unvote();
Amir Levy9659e592016-10-27 18:08:27 +03005770 return 0;
5771
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305772fail_cdev_add:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005773fail_gsi_pre_fw_load_init:
5774 ipa3_dma_shutdown();
5775fail_ipa_dma_setup:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005776 if (ipa3_ctx->use_ipa_pm)
5777 ipa_pm_destroy();
5778 else
Michael Adisumarta3e350812017-09-18 14:54:36 -07005779 ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
Amir Levy9659e592016-10-27 18:08:27 +03005780fail_create_apps_resource:
Michael Adisumarta3e350812017-09-18 14:54:36 -07005781 if (!ipa3_ctx->use_ipa_pm)
5782 ipa_rm_exit();
Amir Levy9659e592016-10-27 18:08:27 +03005783fail_ipa_rm_init:
Skylar Changefc0a0f2018-03-29 11:17:40 -07005784 device_destroy(ipa3_ctx->cdev.class, ipa3_ctx->cdev.dev_num);
Amir Levy9659e592016-10-27 18:08:27 +03005785fail_device_create:
Skylar Changefc0a0f2018-03-29 11:17:40 -07005786 unregister_chrdev_region(ipa3_ctx->cdev.dev_num, 1);
Amir Levy9659e592016-10-27 18:08:27 +03005787fail_alloc_chrdev_region:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005788 idr_destroy(&ipa3_ctx->ipa_idr);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005789 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
5790 idr_destroy(&rset->rule_ids);
5791 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
5792 idr_destroy(&rset->rule_ids);
5793 idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
5794 idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005795 kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
5796fail_rx_pkt_wrapper_cache:
5797 kmem_cache_destroy(ipa3_ctx->tx_pkt_wrapper_cache);
5798fail_tx_pkt_wrapper_cache:
5799 kmem_cache_destroy(ipa3_ctx->rt_tbl_cache);
5800fail_rt_tbl_cache:
5801 kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_offset_cache);
5802fail_hdr_proc_ctx_offset_cache:
5803 kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_cache);
5804fail_hdr_proc_ctx_cache:
5805 kmem_cache_destroy(ipa3_ctx->hdr_offset_cache);
5806fail_hdr_offset_cache:
5807 kmem_cache_destroy(ipa3_ctx->hdr_cache);
5808fail_hdr_cache:
5809 kmem_cache_destroy(ipa3_ctx->rt_rule_cache);
5810fail_rt_rule_cache:
5811 kmem_cache_destroy(ipa3_ctx->flt_rule_cache);
5812fail_flt_rule_cache:
5813 destroy_workqueue(ipa3_ctx->transport_power_mgmt_wq);
5814fail_create_transport_wq:
5815 destroy_workqueue(ipa3_ctx->power_mgmt_wq);
5816fail_init_hw:
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04005817 if (ipa3_ctx->ipa3_hw_mode == IPA_HW_MODE_EMULATION)
5818 ipahal_destroy();
5819fail_ipahal_init:
Amir Levy9659e592016-10-27 18:08:27 +03005820 iounmap(ipa3_ctx->mmio);
5821fail_remap:
5822 ipa3_disable_clks();
5823 ipa3_active_clients_log_destroy();
5824fail_init_active_client:
Ghanim Fodi6a831342017-03-07 18:19:15 +02005825 if (ipa3_clk)
5826 clk_put(ipa3_clk);
5827 ipa3_clk = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03005828fail_clk:
Skylar Changefc0a0f2018-03-29 11:17:40 -07005829 if (ipa3_ctx->ipa_bus_hdl)
5830 msm_bus_scale_unregister_client(ipa3_ctx->ipa_bus_hdl);
Amir Levy9659e592016-10-27 18:08:27 +03005831fail_bus_reg:
Skylar Changefc0a0f2018-03-29 11:17:40 -07005832 if (ipa3_ctx->ctrl->msm_bus_data_ptr)
5833 msm_bus_cl_clear_pdata(ipa3_ctx->ctrl->msm_bus_data_ptr);
Amir Levy9659e592016-10-27 18:08:27 +03005834fail_init_mem_partition:
5835fail_bind:
5836 kfree(ipa3_ctx->ctrl);
5837fail_mem_ctrl:
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005838 kfree(ipa3_ctx->ipa_tz_unlock_reg);
5839fail_tz_unlock_reg:
Skylar Chang841c1452017-04-03 16:07:22 -07005840 if (ipa3_ctx->logbuf)
5841 ipc_log_context_destroy(ipa3_ctx->logbuf);
Amir Levy9659e592016-10-27 18:08:27 +03005842 kfree(ipa3_ctx);
5843 ipa3_ctx = NULL;
5844fail_mem_ctx:
5845 return result;
5846}
5847
Michael Adisumarta3e350812017-09-18 14:54:36 -07005848static int get_ipa_dts_pm_info(struct platform_device *pdev,
5849 struct ipa3_plat_drv_res *ipa_drv_res)
5850{
5851 int result;
5852 int i, j;
5853
5854 ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
5855 "qcom,use-ipa-pm");
5856 IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
5857 if (!ipa_drv_res->use_ipa_pm)
5858 return 0;
5859
5860 result = of_property_read_u32(pdev->dev.of_node,
5861 "qcom,msm-bus,num-cases",
5862 &ipa_drv_res->pm_init.threshold_size);
5863 /* No vote is ignored */
5864 ipa_drv_res->pm_init.threshold_size -= 2;
5865 if (result || ipa_drv_res->pm_init.threshold_size >
5866 IPA_PM_THRESHOLD_MAX) {
5867 IPAERR("invalid property qcom,msm-bus,num-cases %d\n",
5868 ipa_drv_res->pm_init.threshold_size);
5869 return -EFAULT;
5870 }
5871
5872 result = of_property_read_u32_array(pdev->dev.of_node,
5873 "qcom,throughput-threshold",
5874 ipa_drv_res->pm_init.default_threshold,
5875 ipa_drv_res->pm_init.threshold_size);
5876 if (result) {
5877 IPAERR("failed to read qcom,throughput-thresholds\n");
5878 return -EFAULT;
5879 }
5880
5881 result = of_property_count_strings(pdev->dev.of_node,
5882 "qcom,scaling-exceptions");
5883 if (result < 0) {
5884 IPADBG("no exception list for ipa pm\n");
5885 result = 0;
5886 }
5887
5888 if (result % (ipa_drv_res->pm_init.threshold_size + 1)) {
5889 IPAERR("failed to read qcom,scaling-exceptions\n");
5890 return -EFAULT;
5891 }
5892
5893 ipa_drv_res->pm_init.exception_size = result /
5894 (ipa_drv_res->pm_init.threshold_size + 1);
5895 if (ipa_drv_res->pm_init.exception_size >=
5896 IPA_PM_EXCEPTION_MAX) {
5897 IPAERR("exception list larger then max %d\n",
5898 ipa_drv_res->pm_init.exception_size);
5899 return -EFAULT;
5900 }
5901
5902 for (i = 0; i < ipa_drv_res->pm_init.exception_size; i++) {
5903 struct ipa_pm_exception *ex = ipa_drv_res->pm_init.exceptions;
5904
5905 result = of_property_read_string_index(pdev->dev.of_node,
5906 "qcom,scaling-exceptions",
5907 i * ipa_drv_res->pm_init.threshold_size,
5908 &ex[i].usecase);
5909 if (result) {
5910 IPAERR("failed to read qcom,scaling-exceptions");
5911 return -EFAULT;
5912 }
5913
5914 for (j = 0; j < ipa_drv_res->pm_init.threshold_size; j++) {
5915 const char *str;
5916
5917 result = of_property_read_string_index(
5918 pdev->dev.of_node,
5919 "qcom,scaling-exceptions",
5920 i * ipa_drv_res->pm_init.threshold_size + j + 1,
5921 &str);
5922 if (result) {
5923 IPAERR("failed to read qcom,scaling-exceptions"
5924 );
5925 return -EFAULT;
5926 }
5927
5928 if (kstrtou32(str, 0, &ex[i].threshold[j])) {
5929 IPAERR("error str=%s\n", str);
5930 return -EFAULT;
5931 }
5932 }
5933 }
5934
5935 return 0;
5936}
5937
Amir Levy9659e592016-10-27 18:08:27 +03005938static int get_ipa_dts_configuration(struct platform_device *pdev,
5939 struct ipa3_plat_drv_res *ipa_drv_res)
5940{
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005941 int i, result, pos;
Amir Levy9659e592016-10-27 18:08:27 +03005942 struct resource *resource;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005943 u32 *ipa_tz_unlock_reg;
5944 int elem_num;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005945 u32 mhi_evid_limits[2];
Amir Levy9659e592016-10-27 18:08:27 +03005946
5947 /* initialize ipa3_res */
5948 ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
5949 ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
5950 ipa_drv_res->ipa_hw_type = 0;
5951 ipa_drv_res->ipa3_hw_mode = 0;
Amir Levy9659e592016-10-27 18:08:27 +03005952 ipa_drv_res->modem_cfg_emb_pipe_flt = false;
5953 ipa_drv_res->ipa_wdi2 = false;
Mohammed Javid80d0e2a2019-06-10 14:11:42 +05305954 ipa_drv_res->ipa_config_is_auto = false;
Mohammed Javid73cd4d22018-04-03 17:15:49 +05305955 ipa_drv_res->ipa_mhi_dynamic_config = false;
Amir Levy9659e592016-10-27 18:08:27 +03005956 ipa_drv_res->use_64_bit_dma_mask = false;
Ghanim Fodi6a831342017-03-07 18:19:15 +02005957 ipa_drv_res->use_bw_vote = false;
Amir Levy9659e592016-10-27 18:08:27 +03005958 ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
5959 ipa_drv_res->lan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
5960 ipa_drv_res->apply_rg10_wa = false;
5961 ipa_drv_res->gsi_ch20_wa = false;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005962 ipa_drv_res->ipa_tz_unlock_reg_num = 0;
5963 ipa_drv_res->ipa_tz_unlock_reg = NULL;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005964 ipa_drv_res->mhi_evid_limits[0] = IPA_MHI_GSI_EVENT_RING_ID_START;
5965 ipa_drv_res->mhi_evid_limits[1] = IPA_MHI_GSI_EVENT_RING_ID_END;
Amir Levy9659e592016-10-27 18:08:27 +03005966
5967 /* Get IPA HW Version */
5968 result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver",
5969 &ipa_drv_res->ipa_hw_type);
5970 if ((result) || (ipa_drv_res->ipa_hw_type == 0)) {
5971 IPAERR(":get resource failed for ipa-hw-ver!\n");
5972 return -ENODEV;
5973 }
5974 IPADBG(": ipa_hw_type = %d", ipa_drv_res->ipa_hw_type);
5975
5976 if (ipa_drv_res->ipa_hw_type < IPA_HW_v3_0) {
5977 IPAERR(":IPA version below 3.0 not supported!\n");
5978 return -ENODEV;
5979 }
5980
5981 /* Get IPA HW mode */
5982 result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-mode",
5983 &ipa_drv_res->ipa3_hw_mode);
5984 if (result)
5985 IPADBG("using default (IPA_MODE_NORMAL) for ipa-hw-mode\n");
5986 else
5987 IPADBG(": found ipa_drv_res->ipa3_hw_mode = %d",
5988 ipa_drv_res->ipa3_hw_mode);
5989
5990 /* Get IPA WAN / LAN RX pool size */
5991 result = of_property_read_u32(pdev->dev.of_node,
5992 "qcom,wan-rx-ring-size",
5993 &ipa_drv_res->wan_rx_ring_size);
5994 if (result)
5995 IPADBG("using default for wan-rx-ring-size = %u\n",
5996 ipa_drv_res->wan_rx_ring_size);
5997 else
5998 IPADBG(": found ipa_drv_res->wan-rx-ring-size = %u",
5999 ipa_drv_res->wan_rx_ring_size);
6000
6001 result = of_property_read_u32(pdev->dev.of_node,
6002 "qcom,lan-rx-ring-size",
6003 &ipa_drv_res->lan_rx_ring_size);
6004 if (result)
6005 IPADBG("using default for lan-rx-ring-size = %u\n",
6006 ipa_drv_res->lan_rx_ring_size);
6007 else
6008 IPADBG(": found ipa_drv_res->lan-rx-ring-size = %u",
6009 ipa_drv_res->lan_rx_ring_size);
6010
6011 ipa_drv_res->use_ipa_teth_bridge =
6012 of_property_read_bool(pdev->dev.of_node,
6013 "qcom,use-ipa-tethering-bridge");
6014 IPADBG(": using TBDr = %s",
6015 ipa_drv_res->use_ipa_teth_bridge
6016 ? "True" : "False");
6017
Mohammed Javid73cd4d22018-04-03 17:15:49 +05306018 ipa_drv_res->ipa_mhi_dynamic_config =
6019 of_property_read_bool(pdev->dev.of_node,
6020 "qcom,use-ipa-in-mhi-mode");
6021 IPADBG(": ipa_mhi_dynamic_config (%s)\n",
6022 ipa_drv_res->ipa_mhi_dynamic_config
6023 ? "True" : "False");
6024
Amir Levy9659e592016-10-27 18:08:27 +03006025 ipa_drv_res->modem_cfg_emb_pipe_flt =
6026 of_property_read_bool(pdev->dev.of_node,
6027 "qcom,modem-cfg-emb-pipe-flt");
6028 IPADBG(": modem configure embedded pipe filtering = %s\n",
6029 ipa_drv_res->modem_cfg_emb_pipe_flt
6030 ? "True" : "False");
6031
6032 ipa_drv_res->ipa_wdi2 =
6033 of_property_read_bool(pdev->dev.of_node,
6034 "qcom,ipa-wdi2");
6035 IPADBG(": WDI-2.0 = %s\n",
6036 ipa_drv_res->ipa_wdi2
6037 ? "True" : "False");
6038
Mohammed Javid80d0e2a2019-06-10 14:11:42 +05306039 ipa_drv_res->ipa_config_is_auto =
6040 of_property_read_bool(pdev->dev.of_node,
6041 "qcom,ipa-config-is-auto");
6042 IPADBG(": ipa-config-is-auto = %s\n",
6043 ipa_drv_res->ipa_config_is_auto
6044 ? "True" : "False");
6045
Amir Levy9659e592016-10-27 18:08:27 +03006046 ipa_drv_res->use_64_bit_dma_mask =
6047 of_property_read_bool(pdev->dev.of_node,
6048 "qcom,use-64-bit-dma-mask");
6049 IPADBG(": use_64_bit_dma_mask = %s\n",
6050 ipa_drv_res->use_64_bit_dma_mask
6051 ? "True" : "False");
6052
Ghanim Fodi6a831342017-03-07 18:19:15 +02006053 ipa_drv_res->use_bw_vote =
6054 of_property_read_bool(pdev->dev.of_node,
6055 "qcom,bandwidth-vote-for-ipa");
6056 IPADBG(": use_bw_vote = %s\n",
6057 ipa_drv_res->use_bw_vote
6058 ? "True" : "False");
6059
Amir Levy9659e592016-10-27 18:08:27 +03006060 ipa_drv_res->skip_uc_pipe_reset =
6061 of_property_read_bool(pdev->dev.of_node,
6062 "qcom,skip-uc-pipe-reset");
6063 IPADBG(": skip uC pipe reset = %s\n",
6064 ipa_drv_res->skip_uc_pipe_reset
6065 ? "True" : "False");
6066
6067 ipa_drv_res->tethered_flow_control =
6068 of_property_read_bool(pdev->dev.of_node,
6069 "qcom,tethered-flow-control");
6070 IPADBG(": Use apps based flow control = %s\n",
6071 ipa_drv_res->tethered_flow_control
6072 ? "True" : "False");
6073
Amir Levy9659e592016-10-27 18:08:27 +03006074 /* Get IPA wrapper address */
6075 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
6076 "ipa-base");
6077 if (!resource) {
6078 IPAERR(":get resource failed for ipa-base!\n");
6079 return -ENODEV;
6080 }
6081 ipa_drv_res->ipa_mem_base = resource->start;
6082 ipa_drv_res->ipa_mem_size = resource_size(resource);
6083 IPADBG(": ipa-base = 0x%x, size = 0x%x\n",
6084 ipa_drv_res->ipa_mem_base,
6085 ipa_drv_res->ipa_mem_size);
6086
6087 smmu_info.ipa_base = ipa_drv_res->ipa_mem_base;
6088 smmu_info.ipa_size = ipa_drv_res->ipa_mem_size;
6089
Amir Levya59ed3f2017-03-05 17:30:55 +02006090 /* Get IPA GSI address */
6091 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
6092 "gsi-base");
6093 if (!resource) {
6094 IPAERR(":get resource failed for gsi-base!\n");
6095 return -ENODEV;
Amir Levy9659e592016-10-27 18:08:27 +03006096 }
Amir Levya59ed3f2017-03-05 17:30:55 +02006097 ipa_drv_res->transport_mem_base = resource->start;
6098 ipa_drv_res->transport_mem_size = resource_size(resource);
6099 IPADBG(": gsi-base = 0x%x, size = 0x%x\n",
6100 ipa_drv_res->transport_mem_base,
6101 ipa_drv_res->transport_mem_size);
6102
6103 /* Get IPA GSI IRQ number */
6104 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
6105 "gsi-irq");
6106 if (!resource) {
6107 IPAERR(":get resource failed for gsi-irq!\n");
6108 return -ENODEV;
6109 }
6110 ipa_drv_res->transport_irq = resource->start;
6111 IPADBG(": gsi-irq = %d\n", ipa_drv_res->transport_irq);
Amir Levy9659e592016-10-27 18:08:27 +03006112
6113 /* Get IPA pipe mem start ofst */
6114 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
6115 "ipa-pipe-mem");
6116 if (!resource) {
6117 IPADBG(":not using pipe memory - resource nonexisting\n");
6118 } else {
6119 ipa_drv_res->ipa_pipe_mem_start_ofst = resource->start;
6120 ipa_drv_res->ipa_pipe_mem_size = resource_size(resource);
6121 IPADBG(":using pipe memory - at 0x%x of size 0x%x\n",
6122 ipa_drv_res->ipa_pipe_mem_start_ofst,
6123 ipa_drv_res->ipa_pipe_mem_size);
6124 }
6125
6126 /* Get IPA IRQ number */
6127 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
6128 "ipa-irq");
6129 if (!resource) {
6130 IPAERR(":get resource failed for ipa-irq!\n");
6131 return -ENODEV;
6132 }
6133 ipa_drv_res->ipa_irq = resource->start;
6134 IPADBG(":ipa-irq = %d\n", ipa_drv_res->ipa_irq);
6135
6136 result = of_property_read_u32(pdev->dev.of_node, "qcom,ee",
6137 &ipa_drv_res->ee);
6138 if (result)
6139 ipa_drv_res->ee = 0;
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04006140 IPADBG(":ee = %u\n", ipa_drv_res->ee);
Amir Levy9659e592016-10-27 18:08:27 +03006141
6142 ipa_drv_res->apply_rg10_wa =
6143 of_property_read_bool(pdev->dev.of_node,
6144 "qcom,use-rg10-limitation-mitigation");
6145 IPADBG(": Use Register Group 10 limitation mitigation = %s\n",
6146 ipa_drv_res->apply_rg10_wa
6147 ? "True" : "False");
6148
6149 ipa_drv_res->gsi_ch20_wa =
6150 of_property_read_bool(pdev->dev.of_node,
6151 "qcom,do-not-use-ch-gsi-20");
6152 IPADBG(": GSI CH 20 WA is = %s\n",
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04006153 ipa_drv_res->gsi_ch20_wa
Amir Levy9659e592016-10-27 18:08:27 +03006154 ? "Needed" : "Not needed");
6155
Gidon Studinski3021a6f2016-11-10 12:48:48 +02006156 elem_num = of_property_count_elems_of_size(pdev->dev.of_node,
Ghanim Fodic823bc62017-10-21 17:29:53 +03006157 "qcom,mhi-event-ring-id-limits", sizeof(u32));
6158
6159 if (elem_num == 2) {
6160 if (of_property_read_u32_array(pdev->dev.of_node,
6161 "qcom,mhi-event-ring-id-limits", mhi_evid_limits, 2)) {
6162 IPAERR("failed to read mhi event ring id limits\n");
6163 return -EFAULT;
6164 }
6165 if (mhi_evid_limits[0] > mhi_evid_limits[1]) {
6166 IPAERR("mhi event ring id low limit > high limit\n");
6167 return -EFAULT;
6168 }
6169 ipa_drv_res->mhi_evid_limits[0] = mhi_evid_limits[0];
6170 ipa_drv_res->mhi_evid_limits[1] = mhi_evid_limits[1];
6171 IPADBG(": mhi-event-ring-id-limits start=%u end=%u\n",
6172 mhi_evid_limits[0], mhi_evid_limits[1]);
6173 } else {
6174 if (elem_num > 0) {
6175 IPAERR("Invalid mhi event ring id limits number %d\n",
6176 elem_num);
6177 return -EINVAL;
6178 }
6179 IPADBG("use default mhi evt ring id limits start=%u end=%u\n",
6180 ipa_drv_res->mhi_evid_limits[0],
6181 ipa_drv_res->mhi_evid_limits[1]);
6182 }
6183
6184 elem_num = of_property_count_elems_of_size(pdev->dev.of_node,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02006185 "qcom,ipa-tz-unlock-reg", sizeof(u32));
6186
6187 if (elem_num > 0 && elem_num % 2 == 0) {
6188 ipa_drv_res->ipa_tz_unlock_reg_num = elem_num / 2;
6189
6190 ipa_tz_unlock_reg = kcalloc(elem_num, sizeof(u32), GFP_KERNEL);
6191 if (ipa_tz_unlock_reg == NULL)
6192 return -ENOMEM;
6193
6194 ipa_drv_res->ipa_tz_unlock_reg = kcalloc(
6195 ipa_drv_res->ipa_tz_unlock_reg_num,
6196 sizeof(*ipa_drv_res->ipa_tz_unlock_reg),
6197 GFP_KERNEL);
6198 if (ipa_drv_res->ipa_tz_unlock_reg == NULL) {
6199 kfree(ipa_tz_unlock_reg);
6200 return -ENOMEM;
6201 }
6202
6203 if (of_property_read_u32_array(pdev->dev.of_node,
6204 "qcom,ipa-tz-unlock-reg", ipa_tz_unlock_reg,
6205 elem_num)) {
6206 IPAERR("failed to read register addresses\n");
6207 kfree(ipa_tz_unlock_reg);
6208 kfree(ipa_drv_res->ipa_tz_unlock_reg);
6209 return -EFAULT;
6210 }
6211
6212 pos = 0;
6213 for (i = 0; i < ipa_drv_res->ipa_tz_unlock_reg_num; i++) {
6214 ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr =
6215 ipa_tz_unlock_reg[pos++];
6216 ipa_drv_res->ipa_tz_unlock_reg[i].size =
6217 ipa_tz_unlock_reg[pos++];
Skylar Chang48afa052017-10-25 09:32:57 -07006218 IPADBG("tz unlock reg %d: addr 0x%pa size %llu\n", i,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02006219 &ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr,
6220 ipa_drv_res->ipa_tz_unlock_reg[i].size);
6221 }
6222 kfree(ipa_tz_unlock_reg);
6223 }
Michael Adisumarta3e350812017-09-18 14:54:36 -07006224
6225 /* get IPA PM related information */
6226 result = get_ipa_dts_pm_info(pdev, ipa_drv_res);
6227 if (result) {
6228 IPAERR("failed to get pm info from dts %d\n", result);
6229 return result;
6230 }
6231
Mohammed Javid03854df2018-06-20 18:36:57 +05306232 ipa_drv_res->wdi_over_pcie =
Ghanim Fodi0ef92fc2018-07-08 11:21:31 +03006233 of_property_read_bool(pdev->dev.of_node,
6234 "qcom,wlan-ce-db-over-pcie");
Mohammed Javid03854df2018-06-20 18:36:57 +05306235 IPADBG("Is wdi_over_pcie ? (%s)\n",
Ghanim Fodi0ef92fc2018-07-08 11:21:31 +03006236 ipa_drv_res->wdi_over_pcie ? "Yes":"No");
Mohammed Javid03854df2018-06-20 18:36:57 +05306237
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04006238 /*
6239 * If we're on emulator, get its interrupt controller's mem
6240 * start and size
6241 */
6242 if (ipa_drv_res->ipa3_hw_mode == IPA_HW_MODE_EMULATION) {
6243 resource = platform_get_resource_byname(
6244 pdev, IORESOURCE_MEM, "intctrl-base");
6245 if (!resource) {
6246 IPAERR(":Can't find intctrl-base resource\n");
6247 return -ENODEV;
6248 }
6249 ipa_drv_res->emulator_intcntrlr_mem_base =
6250 resource->start;
6251 ipa_drv_res->emulator_intcntrlr_mem_size =
6252 resource_size(resource);
6253 IPADBG(":using intctrl-base at 0x%x of size 0x%x\n",
6254 ipa_drv_res->emulator_intcntrlr_mem_base,
6255 ipa_drv_res->emulator_intcntrlr_mem_size);
6256 }
6257
Amir Levy9659e592016-10-27 18:08:27 +03006258 return 0;
6259}
6260
6261static int ipa_smmu_wlan_cb_probe(struct device *dev)
6262{
Skylar Changefc0a0f2018-03-29 11:17:40 -07006263 struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_WLAN);
Amir Levy9659e592016-10-27 18:08:27 +03006264 int atomic_ctx = 1;
6265 int fast = 1;
6266 int bypass = 1;
6267 int ret;
6268 u32 add_map_size;
6269 const u32 *add_map;
6270 int i;
6271
6272 IPADBG("sub pdev=%p\n", dev);
6273
Skylar Changefc0a0f2018-03-29 11:17:40 -07006274 if (!smmu_info.present[IPA_SMMU_CB_WLAN]) {
6275 IPAERR("WLAN SMMU is disabled\n");
6276 return 0;
6277 }
6278
Amir Levy9659e592016-10-27 18:08:27 +03006279 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02006280 cb->iommu = iommu_domain_alloc(dev->bus);
Amir Levy9659e592016-10-27 18:08:27 +03006281 if (!cb->iommu) {
6282 IPAERR("could not alloc iommu domain\n");
6283 /* assume this failure is because iommu driver is not ready */
6284 return -EPROBE_DEFER;
6285 }
6286 cb->valid = true;
6287
Skylar Changefc0a0f2018-03-29 11:17:40 -07006288 if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass") ||
6289 ipa3_ctx->ipa_config_is_mhi) {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006290 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = true;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07006291 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN] = true;
6292
Amir Levy9659e592016-10-27 18:08:27 +03006293 if (iommu_domain_set_attr(cb->iommu,
6294 DOMAIN_ATTR_S1_BYPASS,
6295 &bypass)) {
6296 IPAERR("couldn't set bypass\n");
6297 cb->valid = false;
6298 return -EIO;
6299 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006300 IPADBG("WLAN SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03006301 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006302 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = false;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07006303 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN] = false;
6304
Amir Levy9659e592016-10-27 18:08:27 +03006305 if (iommu_domain_set_attr(cb->iommu,
6306 DOMAIN_ATTR_ATOMIC,
6307 &atomic_ctx)) {
6308 IPAERR("couldn't disable coherent HTW\n");
6309 cb->valid = false;
6310 return -EIO;
6311 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006312 IPADBG(" WLAN SMMU ATTR ATOMIC\n");
Amir Levy9659e592016-10-27 18:08:27 +03006313
6314 if (smmu_info.fast_map) {
6315 if (iommu_domain_set_attr(cb->iommu,
6316 DOMAIN_ATTR_FAST,
6317 &fast)) {
6318 IPAERR("couldn't set fast map\n");
6319 cb->valid = false;
6320 return -EIO;
6321 }
6322 IPADBG("SMMU fast map set\n");
6323 }
6324 }
6325
Michael Adisumarta93e97522017-10-06 15:49:46 -07006326 pr_info("IPA smmu_info.s1_bypass_arr[WLAN]=%d smmu_info.fast_map=%d\n",
6327 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN], smmu_info.fast_map);
6328
Amir Levy9659e592016-10-27 18:08:27 +03006329 ret = iommu_attach_device(cb->iommu, dev);
6330 if (ret) {
6331 IPAERR("could not attach device ret=%d\n", ret);
6332 cb->valid = false;
6333 return ret;
6334 }
6335 /* MAP ipa-uc ram */
6336 add_map = of_get_property(dev->of_node,
6337 "qcom,additional-mapping", &add_map_size);
6338 if (add_map) {
6339 /* mapping size is an array of 3-tuple of u32 */
6340 if (add_map_size % (3 * sizeof(u32))) {
6341 IPAERR("wrong additional mapping format\n");
6342 cb->valid = false;
6343 return -EFAULT;
6344 }
6345
6346 /* iterate of each entry of the additional mapping array */
6347 for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
6348 u32 iova = be32_to_cpu(add_map[i]);
6349 u32 pa = be32_to_cpu(add_map[i + 1]);
6350 u32 size = be32_to_cpu(add_map[i + 2]);
6351 unsigned long iova_p;
6352 phys_addr_t pa_p;
6353 u32 size_p;
6354
6355 IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
6356 iova_p, pa_p, size_p);
6357 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
6358 iova_p, &pa_p, size_p);
6359 ipa3_iommu_map(cb->iommu,
6360 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02006361 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03006362 }
6363 }
6364 return 0;
6365}
6366
6367static int ipa_smmu_uc_cb_probe(struct device *dev)
6368{
Skylar Changefc0a0f2018-03-29 11:17:40 -07006369 struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC);
Amir Levy9659e592016-10-27 18:08:27 +03006370 int atomic_ctx = 1;
6371 int bypass = 1;
6372 int fast = 1;
6373 int ret;
6374 u32 iova_ap_mapping[2];
6375
6376 IPADBG("UC CB PROBE sub pdev=%p\n", dev);
6377
Skylar Changefc0a0f2018-03-29 11:17:40 -07006378 if (!smmu_info.present[IPA_SMMU_CB_UC]) {
6379 IPAERR("UC SMMU is disabled\n");
6380 return 0;
6381 }
6382
Amir Levy9659e592016-10-27 18:08:27 +03006383 ret = of_property_read_u32_array(dev->of_node, "qcom,iova-mapping",
6384 iova_ap_mapping, 2);
6385 if (ret) {
6386 IPAERR("Fail to read UC start/size iova addresses\n");
6387 return ret;
6388 }
6389 cb->va_start = iova_ap_mapping[0];
6390 cb->va_size = iova_ap_mapping[1];
6391 cb->va_end = cb->va_start + cb->va_size;
6392 IPADBG("UC va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
6393
6394 if (smmu_info.use_64_bit_dma_mask) {
6395 if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
6396 dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
6397 IPAERR("DMA set 64bit mask failed\n");
6398 return -EOPNOTSUPP;
6399 }
6400 } else {
6401 if (dma_set_mask(dev, DMA_BIT_MASK(32)) ||
6402 dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
6403 IPAERR("DMA set 32bit mask failed\n");
6404 return -EOPNOTSUPP;
6405 }
6406 }
6407 IPADBG("UC CB PROBE=%p create IOMMU mapping\n", dev);
6408
6409 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02006410 cb->mapping = arm_iommu_create_mapping(dev->bus,
Amir Levy9659e592016-10-27 18:08:27 +03006411 cb->va_start, cb->va_size);
6412 if (IS_ERR_OR_NULL(cb->mapping)) {
6413 IPADBG("Fail to create mapping\n");
6414 /* assume this failure is because iommu driver is not ready */
6415 return -EPROBE_DEFER;
6416 }
6417 IPADBG("SMMU mapping created\n");
6418 cb->valid = true;
6419
Amir Levy9659e592016-10-27 18:08:27 +03006420 IPADBG("UC CB PROBE sub pdev=%p set attribute\n", dev);
Michael Adisumarta93e97522017-10-06 15:49:46 -07006421
Skylar Changefc0a0f2018-03-29 11:17:40 -07006422 if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass") ||
6423 ipa3_ctx->ipa_config_is_mhi) {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006424 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC] = true;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07006425 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = true;
6426
Amir Levy9659e592016-10-27 18:08:27 +03006427 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07006428 DOMAIN_ATTR_S1_BYPASS,
6429 &bypass)) {
Amir Levy9659e592016-10-27 18:08:27 +03006430 IPAERR("couldn't set bypass\n");
6431 arm_iommu_release_mapping(cb->mapping);
6432 cb->valid = false;
6433 return -EIO;
6434 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006435 IPADBG("UC SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03006436 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006437 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC] = false;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07006438 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = false;
6439
Amir Levy9659e592016-10-27 18:08:27 +03006440 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07006441 DOMAIN_ATTR_ATOMIC,
6442 &atomic_ctx)) {
Amir Levy9659e592016-10-27 18:08:27 +03006443 IPAERR("couldn't set domain as atomic\n");
6444 arm_iommu_release_mapping(cb->mapping);
6445 cb->valid = false;
6446 return -EIO;
6447 }
6448 IPADBG("SMMU atomic set\n");
6449
6450 if (smmu_info.fast_map) {
6451 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07006452 DOMAIN_ATTR_FAST,
6453 &fast)) {
Amir Levy9659e592016-10-27 18:08:27 +03006454 IPAERR("couldn't set fast map\n");
6455 arm_iommu_release_mapping(cb->mapping);
6456 cb->valid = false;
6457 return -EIO;
6458 }
6459 IPADBG("SMMU fast map set\n");
6460 }
6461 }
6462
Michael Adisumarta93e97522017-10-06 15:49:46 -07006463 pr_info("IPA smmu_info.s1_bypass_arr[UC]=%d smmu_info.fast_map=%d\n",
6464 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC], smmu_info.fast_map);
6465
Amir Levy9659e592016-10-27 18:08:27 +03006466 IPADBG("UC CB PROBE sub pdev=%p attaching IOMMU device\n", dev);
6467 ret = arm_iommu_attach_device(cb->dev, cb->mapping);
6468 if (ret) {
6469 IPAERR("could not attach device ret=%d\n", ret);
6470 arm_iommu_release_mapping(cb->mapping);
6471 cb->valid = false;
6472 return ret;
6473 }
6474
6475 cb->next_addr = cb->va_end;
6476 ipa3_ctx->uc_pdev = dev;
6477
6478 return 0;
6479}
6480
6481static int ipa_smmu_ap_cb_probe(struct device *dev)
6482{
Skylar Changefc0a0f2018-03-29 11:17:40 -07006483 struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
Amir Levy9659e592016-10-27 18:08:27 +03006484 int result;
Amir Levy9659e592016-10-27 18:08:27 +03006485 int atomic_ctx = 1;
6486 int fast = 1;
6487 int bypass = 1;
6488 u32 iova_ap_mapping[2];
6489 u32 add_map_size;
Mohammed Javid36d13cf2018-01-26 22:49:03 +05306490 u32 q6_smem_size;
Amir Levy9659e592016-10-27 18:08:27 +03006491 const u32 *add_map;
6492 void *smem_addr;
6493 int i;
6494
6495 IPADBG("AP CB probe: sub pdev=%p\n", dev);
6496
Skylar Changefc0a0f2018-03-29 11:17:40 -07006497 if (!smmu_info.present[IPA_SMMU_CB_AP]) {
6498 IPAERR("AP SMMU is disabled");
6499 return 0;
6500 }
6501
Amir Levy9659e592016-10-27 18:08:27 +03006502 result = of_property_read_u32_array(dev->of_node, "qcom,iova-mapping",
6503 iova_ap_mapping, 2);
6504 if (result) {
6505 IPAERR("Fail to read AP start/size iova addresses\n");
6506 return result;
6507 }
6508 cb->va_start = iova_ap_mapping[0];
6509 cb->va_size = iova_ap_mapping[1];
6510 cb->va_end = cb->va_start + cb->va_size;
6511 IPADBG("AP va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
6512
6513 if (smmu_info.use_64_bit_dma_mask) {
6514 if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
6515 dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
6516 IPAERR("DMA set 64bit mask failed\n");
6517 return -EOPNOTSUPP;
6518 }
6519 } else {
6520 if (dma_set_mask(dev, DMA_BIT_MASK(32)) ||
6521 dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
6522 IPAERR("DMA set 32bit mask failed\n");
6523 return -EOPNOTSUPP;
6524 }
6525 }
6526
6527 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02006528 cb->mapping = arm_iommu_create_mapping(dev->bus,
Amir Levy9659e592016-10-27 18:08:27 +03006529 cb->va_start, cb->va_size);
6530 if (IS_ERR_OR_NULL(cb->mapping)) {
6531 IPADBG("Fail to create mapping\n");
6532 /* assume this failure is because iommu driver is not ready */
6533 return -EPROBE_DEFER;
6534 }
6535 IPADBG("SMMU mapping created\n");
6536 cb->valid = true;
6537
Michael Adisumarta93e97522017-10-06 15:49:46 -07006538 if (of_property_read_bool(dev->of_node,
Skylar Changefc0a0f2018-03-29 11:17:40 -07006539 "qcom,smmu-s1-bypass") || ipa3_ctx->ipa_config_is_mhi) {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006540 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP] = true;
Skylar Change87894f2018-04-02 15:49:12 -07006541 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] = true;
Amir Levy9659e592016-10-27 18:08:27 +03006542 if (iommu_domain_set_attr(cb->mapping->domain,
6543 DOMAIN_ATTR_S1_BYPASS,
6544 &bypass)) {
6545 IPAERR("couldn't set bypass\n");
6546 arm_iommu_release_mapping(cb->mapping);
6547 cb->valid = false;
6548 return -EIO;
6549 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006550 IPADBG("AP/USB SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03006551 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006552 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP] = false;
Skylar Change87894f2018-04-02 15:49:12 -07006553 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] = false;
Amir Levy9659e592016-10-27 18:08:27 +03006554 if (iommu_domain_set_attr(cb->mapping->domain,
6555 DOMAIN_ATTR_ATOMIC,
6556 &atomic_ctx)) {
6557 IPAERR("couldn't set domain as atomic\n");
6558 arm_iommu_release_mapping(cb->mapping);
6559 cb->valid = false;
6560 return -EIO;
6561 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006562 IPADBG("AP/USB SMMU atomic set\n");
Amir Levy9659e592016-10-27 18:08:27 +03006563
Skylar Chang578e1a42018-06-15 10:33:26 -07006564 if (smmu_info.fast_map) {
6565 if (iommu_domain_set_attr(cb->mapping->domain,
Amir Levy9659e592016-10-27 18:08:27 +03006566 DOMAIN_ATTR_FAST,
6567 &fast)) {
Skylar Chang578e1a42018-06-15 10:33:26 -07006568 IPAERR("couldn't set fast map\n");
6569 arm_iommu_release_mapping(cb->mapping);
6570 cb->valid = false;
6571 return -EIO;
6572 }
6573 IPADBG("SMMU fast map set\n");
Amir Levy9659e592016-10-27 18:08:27 +03006574 }
Amir Levy9659e592016-10-27 18:08:27 +03006575 }
6576
Michael Adisumarta93e97522017-10-06 15:49:46 -07006577 pr_info("IPA smmu_info.s1_bypass_arr[AP]=%d smmu_info.fast_map=%d\n",
6578 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP], smmu_info.fast_map);
6579
Amir Levy9659e592016-10-27 18:08:27 +03006580 result = arm_iommu_attach_device(cb->dev, cb->mapping);
6581 if (result) {
6582 IPAERR("couldn't attach to IOMMU ret=%d\n", result);
6583 cb->valid = false;
6584 return result;
6585 }
6586
6587 add_map = of_get_property(dev->of_node,
6588 "qcom,additional-mapping", &add_map_size);
6589 if (add_map) {
6590 /* mapping size is an array of 3-tuple of u32 */
6591 if (add_map_size % (3 * sizeof(u32))) {
6592 IPAERR("wrong additional mapping format\n");
6593 cb->valid = false;
6594 return -EFAULT;
6595 }
6596
6597 /* iterate of each entry of the additional mapping array */
6598 for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
6599 u32 iova = be32_to_cpu(add_map[i]);
6600 u32 pa = be32_to_cpu(add_map[i + 1]);
6601 u32 size = be32_to_cpu(add_map[i + 2]);
6602 unsigned long iova_p;
6603 phys_addr_t pa_p;
6604 u32 size_p;
6605
6606 IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
6607 iova_p, pa_p, size_p);
6608 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
6609 iova_p, &pa_p, size_p);
6610 ipa3_iommu_map(cb->mapping->domain,
6611 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02006612 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03006613 }
6614 }
6615
Mohammed Javid36d13cf2018-01-26 22:49:03 +05306616 result = of_property_read_u32_array(dev->of_node,
6617 "qcom,ipa-q6-smem-size", &q6_smem_size, 1);
6618 if (result) {
6619 IPADBG("ipa q6 smem size = %d\n", IPA_SMEM_SIZE);
6620 /* map SMEM memory for IPA table accesses */
6621 smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
6622 SMEM_MODEM, 0);
Chaitanya Pratapa4c38c592019-07-31 19:56:44 +05306623 q6_smem_size = IPA_SMEM_SIZE;
Mohammed Javid36d13cf2018-01-26 22:49:03 +05306624 } else {
6625 IPADBG("ipa q6 smem size = %d\n", q6_smem_size);
6626 smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, q6_smem_size,
6627 SMEM_MODEM, 0);
6628 }
Amir Levy9659e592016-10-27 18:08:27 +03006629 if (smem_addr) {
6630 phys_addr_t iova = smem_virt_to_phys(smem_addr);
6631 phys_addr_t pa = iova;
6632 unsigned long iova_p;
6633 phys_addr_t pa_p;
6634 u32 size_p;
6635
Chaitanya Pratapa4c38c592019-07-31 19:56:44 +05306636 IPA_SMMU_ROUND_TO_PAGE(iova, pa, q6_smem_size,
Amir Levy9659e592016-10-27 18:08:27 +03006637 iova_p, pa_p, size_p);
6638 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
6639 iova_p, &pa_p, size_p);
6640 ipa3_iommu_map(cb->mapping->domain,
6641 iova_p, pa_p, size_p,
Skylar Chang2d1a7622018-05-30 17:01:58 -07006642 IOMMU_READ | IOMMU_WRITE);
Amir Levy9659e592016-10-27 18:08:27 +03006643 }
6644
6645
Skylar Changefc0a0f2018-03-29 11:17:40 -07006646 smmu_info.present[IPA_SMMU_CB_AP] = true;
6647 ipa3_ctx->pdev = dev;
Amir Levy9659e592016-10-27 18:08:27 +03006648
Michael Adisumartac8c404a2018-04-05 18:01:45 -07006649 return 0;
Amir Levy9659e592016-10-27 18:08:27 +03006650}
6651
Skylar Changefc0a0f2018-03-29 11:17:40 -07006652static int ipa_smmu_cb_probe(struct device *dev, enum ipa_smmu_cb_type cb_type)
6653{
6654 switch (cb_type) {
6655 case IPA_SMMU_CB_AP:
6656 return ipa_smmu_ap_cb_probe(dev);
6657 case IPA_SMMU_CB_WLAN:
6658 return ipa_smmu_wlan_cb_probe(dev);
6659 case IPA_SMMU_CB_UC:
6660 return ipa_smmu_uc_cb_probe(dev);
6661 case IPA_SMMU_CB_MAX:
6662 IPAERR("Invalid cb_type\n");
6663 }
6664 return 0;
6665}
6666
6667static int ipa3_attach_to_smmu(void)
6668{
6669 struct ipa_smmu_cb_ctx *cb;
6670 int i, result;
6671
6672 ipa3_ctx->pdev = &ipa3_ctx->master_pdev->dev;
6673 ipa3_ctx->uc_pdev = &ipa3_ctx->master_pdev->dev;
6674
6675 if (smmu_info.arm_smmu) {
6676 IPADBG("smmu is enabled\n");
6677 for (i = 0; i < IPA_SMMU_CB_MAX; i++) {
6678 cb = ipa3_get_smmu_ctx(i);
6679 result = ipa_smmu_cb_probe(cb->dev, i);
6680 if (result)
6681 IPAERR("probe failed for cb %d\n", i);
6682 }
6683 } else {
6684 IPADBG("smmu is disabled\n");
6685 }
6686 return 0;
6687}
6688
Amir Levy9659e592016-10-27 18:08:27 +03006689static irqreturn_t ipa3_smp2p_modem_clk_query_isr(int irq, void *ctxt)
6690{
6691 ipa3_freeze_clock_vote_and_notify_modem();
6692
6693 return IRQ_HANDLED;
6694}
6695
6696static int ipa3_smp2p_probe(struct device *dev)
6697{
6698 struct device_node *node = dev->of_node;
6699 int res;
6700
Mohammed Javid7de12702017-07-21 15:22:58 +05306701 if (ipa3_ctx == NULL) {
6702 IPAERR("ipa3_ctx was not initialized\n");
6703 return -ENXIO;
6704 }
Amir Levy9659e592016-10-27 18:08:27 +03006705 IPADBG("node->name=%s\n", node->name);
6706 if (strcmp("qcom,smp2pgpio_map_ipa_1_out", node->name) == 0) {
6707 res = of_get_gpio(node, 0);
6708 if (res < 0) {
6709 IPADBG("of_get_gpio returned %d\n", res);
6710 return res;
6711 }
6712
6713 ipa3_ctx->smp2p_info.out_base_id = res;
6714 IPADBG("smp2p out_base_id=%d\n",
6715 ipa3_ctx->smp2p_info.out_base_id);
6716 } else if (strcmp("qcom,smp2pgpio_map_ipa_1_in", node->name) == 0) {
6717 int irq;
6718
6719 res = of_get_gpio(node, 0);
6720 if (res < 0) {
6721 IPADBG("of_get_gpio returned %d\n", res);
6722 return res;
6723 }
6724
6725 ipa3_ctx->smp2p_info.in_base_id = res;
6726 IPADBG("smp2p in_base_id=%d\n",
6727 ipa3_ctx->smp2p_info.in_base_id);
6728
6729 /* register for modem clk query */
6730 irq = gpio_to_irq(ipa3_ctx->smp2p_info.in_base_id +
6731 IPA_GPIO_IN_QUERY_CLK_IDX);
6732 if (irq < 0) {
6733 IPAERR("gpio_to_irq failed %d\n", irq);
6734 return -ENODEV;
6735 }
6736 IPADBG("smp2p irq#=%d\n", irq);
6737 res = request_irq(irq,
6738 (irq_handler_t)ipa3_smp2p_modem_clk_query_isr,
6739 IRQF_TRIGGER_RISING, "ipa_smp2p_clk_vote", dev);
6740 if (res) {
6741 IPAERR("fail to register smp2p irq=%d\n", irq);
6742 return -ENODEV;
6743 }
6744 res = enable_irq_wake(ipa3_ctx->smp2p_info.in_base_id +
6745 IPA_GPIO_IN_QUERY_CLK_IDX);
6746 if (res)
6747 IPAERR("failed to enable irq wake\n");
6748 }
6749
6750 return 0;
6751}
6752
6753int ipa3_plat_drv_probe(struct platform_device *pdev_p,
6754 struct ipa_api_controller *api_ctrl,
6755 const struct of_device_id *pdrv_match)
6756{
6757 int result;
6758 struct device *dev = &pdev_p->dev;
Skylar Changefc0a0f2018-03-29 11:17:40 -07006759 struct ipa_smmu_cb_ctx *cb;
Amir Levy9659e592016-10-27 18:08:27 +03006760
6761 IPADBG("IPA driver probing started\n");
6762 IPADBG("dev->of_node->name = %s\n", dev->of_node->name);
6763
Skylar Changefc0a0f2018-03-29 11:17:40 -07006764 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-ap-cb")) {
6765 cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
6766 cb->dev = dev;
6767 smmu_info.present[IPA_SMMU_CB_AP] = true;
Amir Levy9659e592016-10-27 18:08:27 +03006768
Skylar Changefc0a0f2018-03-29 11:17:40 -07006769 return 0;
6770 }
Amir Levy9659e592016-10-27 18:08:27 +03006771
Skylar Changefc0a0f2018-03-29 11:17:40 -07006772 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-wlan-cb")) {
6773 cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_WLAN);
6774 cb->dev = dev;
6775 smmu_info.present[IPA_SMMU_CB_WLAN] = true;
6776
6777 return 0;
6778 }
6779
6780 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-uc-cb")) {
6781 cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC);
6782 cb->dev = dev;
6783 smmu_info.present[IPA_SMMU_CB_UC] = true;
6784
6785 return 0;
6786 }
Amir Levy9659e592016-10-27 18:08:27 +03006787
6788 if (of_device_is_compatible(dev->of_node,
6789 "qcom,smp2pgpio-map-ipa-1-in"))
6790 return ipa3_smp2p_probe(dev);
6791
6792 if (of_device_is_compatible(dev->of_node,
6793 "qcom,smp2pgpio-map-ipa-1-out"))
6794 return ipa3_smp2p_probe(dev);
6795
Amir Levy9659e592016-10-27 18:08:27 +03006796 result = get_ipa_dts_configuration(pdev_p, &ipa3_res);
6797 if (result) {
6798 IPAERR("IPA dts parsing failed\n");
6799 return result;
6800 }
6801
6802 result = ipa3_bind_api_controller(ipa3_res.ipa_hw_type, api_ctrl);
6803 if (result) {
6804 IPAERR("IPA API binding failed\n");
6805 return result;
6806 }
6807
Amir Levy9659e592016-10-27 18:08:27 +03006808 if (of_property_read_bool(pdev_p->dev.of_node, "qcom,arm-smmu")) {
6809 if (of_property_read_bool(pdev_p->dev.of_node,
Amir Levy9659e592016-10-27 18:08:27 +03006810 "qcom,smmu-fast-map"))
6811 smmu_info.fast_map = true;
6812 if (of_property_read_bool(pdev_p->dev.of_node,
6813 "qcom,use-64-bit-dma-mask"))
6814 smmu_info.use_64_bit_dma_mask = true;
6815 smmu_info.arm_smmu = true;
Amir Levy9659e592016-10-27 18:08:27 +03006816 } else if (of_property_read_bool(pdev_p->dev.of_node,
6817 "qcom,msm-smmu")) {
6818 IPAERR("Legacy IOMMU not supported\n");
6819 result = -EOPNOTSUPP;
6820 } else {
6821 if (of_property_read_bool(pdev_p->dev.of_node,
6822 "qcom,use-64-bit-dma-mask")) {
6823 if (dma_set_mask(&pdev_p->dev, DMA_BIT_MASK(64)) ||
6824 dma_set_coherent_mask(&pdev_p->dev,
6825 DMA_BIT_MASK(64))) {
6826 IPAERR("DMA set 64bit mask failed\n");
6827 return -EOPNOTSUPP;
6828 }
6829 } else {
6830 if (dma_set_mask(&pdev_p->dev, DMA_BIT_MASK(32)) ||
6831 dma_set_coherent_mask(&pdev_p->dev,
6832 DMA_BIT_MASK(32))) {
6833 IPAERR("DMA set 32bit mask failed\n");
6834 return -EOPNOTSUPP;
6835 }
6836 }
Skylar Changefc0a0f2018-03-29 11:17:40 -07006837 }
Amir Levy9659e592016-10-27 18:08:27 +03006838
Skylar Changefc0a0f2018-03-29 11:17:40 -07006839 /* Proceed to real initialization */
6840 result = ipa3_pre_init(&ipa3_res, pdev_p);
6841 if (result) {
6842 IPAERR("ipa3_init failed\n");
6843 return result;
Amir Levy9659e592016-10-27 18:08:27 +03006844 }
6845
Ghanim Fodi115bf8a2017-04-21 01:36:06 -07006846 result = of_platform_populate(pdev_p->dev.of_node,
6847 pdrv_match, NULL, &pdev_p->dev);
6848 if (result) {
6849 IPAERR("failed to populate platform\n");
6850 return result;
6851 }
6852
Amir Levy9659e592016-10-27 18:08:27 +03006853 return result;
6854}
6855
6856/**
6857 * ipa3_ap_suspend() - suspend callback for runtime_pm
6858 * @dev: pointer to device
6859 *
6860 * This callback will be invoked by the runtime_pm framework when an AP suspend
6861 * operation is invoked, usually by pressing a suspend button.
6862 *
6863 * Returns -EAGAIN to runtime_pm framework in case IPA is in use by AP.
6864 * This will postpone the suspend operation until IPA is no longer used by AP.
Skylar Chang68c37d82018-04-07 16:42:36 -07006865 */
Amir Levy9659e592016-10-27 18:08:27 +03006866int ipa3_ap_suspend(struct device *dev)
6867{
6868 int i;
6869
6870 IPADBG("Enter...\n");
6871
6872 /* In case there is a tx/rx handler in polling mode fail to suspend */
6873 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
6874 if (ipa3_ctx->ep[i].sys &&
6875 atomic_read(&ipa3_ctx->ep[i].sys->curr_polling_state)) {
6876 IPAERR("EP %d is in polling state, do not suspend\n",
6877 i);
6878 return -EAGAIN;
6879 }
6880 }
6881
Michael Adisumarta3e350812017-09-18 14:54:36 -07006882 if (ipa3_ctx->use_ipa_pm) {
6883 ipa_pm_deactivate_all_deferred();
6884 } else {
6885 /*
6886 * Release transport IPA resource without waiting
6887 * for inactivity timer
6888 */
6889 atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
6890 ipa3_transport_release_resource(NULL);
6891 }
Amir Levy9659e592016-10-27 18:08:27 +03006892 IPADBG("Exit\n");
6893
6894 return 0;
6895}
6896
6897/**
Skylar Chang68c37d82018-04-07 16:42:36 -07006898 * ipa3_ap_resume() - resume callback for runtime_pm
6899 * @dev: pointer to device
6900 *
6901 * This callback will be invoked by the runtime_pm framework when an AP resume
6902 * operation is invoked.
6903 *
6904 * Always returns 0 since resume should always succeed.
6905 */
Amir Levy9659e592016-10-27 18:08:27 +03006906int ipa3_ap_resume(struct device *dev)
6907{
6908 return 0;
6909}
6910
6911struct ipa3_context *ipa3_get_ctx(void)
6912{
6913 return ipa3_ctx;
6914}
6915
Amir Levy8fb98e02019-10-29 14:22:26 +02006916bool ipa3_get_lan_rx_napi(void)
6917{
6918 return false;
6919}
6920
Amir Levy9659e592016-10-27 18:08:27 +03006921static void ipa_gsi_notify_cb(struct gsi_per_notify *notify)
6922{
6923 switch (notify->evt_id) {
6924 case GSI_PER_EVT_GLOB_ERROR:
6925 IPAERR("Got GSI_PER_EVT_GLOB_ERROR\n");
6926 IPAERR("Err_desc = 0x%04x\n", notify->data.err_desc);
6927 break;
6928 case GSI_PER_EVT_GLOB_GP1:
6929 IPAERR("Got GSI_PER_EVT_GLOB_GP1\n");
6930 BUG();
6931 break;
6932 case GSI_PER_EVT_GLOB_GP2:
6933 IPAERR("Got GSI_PER_EVT_GLOB_GP2\n");
6934 BUG();
6935 break;
6936 case GSI_PER_EVT_GLOB_GP3:
6937 IPAERR("Got GSI_PER_EVT_GLOB_GP3\n");
6938 BUG();
6939 break;
6940 case GSI_PER_EVT_GENERAL_BREAK_POINT:
6941 IPAERR("Got GSI_PER_EVT_GENERAL_BREAK_POINT\n");
6942 break;
6943 case GSI_PER_EVT_GENERAL_BUS_ERROR:
6944 IPAERR("Got GSI_PER_EVT_GENERAL_BUS_ERROR\n");
6945 BUG();
6946 break;
6947 case GSI_PER_EVT_GENERAL_CMD_FIFO_OVERFLOW:
6948 IPAERR("Got GSI_PER_EVT_GENERAL_CMD_FIFO_OVERFLOW\n");
6949 BUG();
6950 break;
6951 case GSI_PER_EVT_GENERAL_MCS_STACK_OVERFLOW:
6952 IPAERR("Got GSI_PER_EVT_GENERAL_MCS_STACK_OVERFLOW\n");
6953 BUG();
6954 break;
6955 default:
6956 IPAERR("Received unexpected evt: %d\n",
6957 notify->evt_id);
6958 BUG();
6959 }
6960}
6961
6962int ipa3_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data)
6963{
6964 struct ipa3_ready_cb_info *cb_info = NULL;
6965
6966 /* check ipa3_ctx existed or not */
6967 if (!ipa3_ctx) {
6968 IPADBG("IPA driver haven't initialized\n");
6969 return -ENXIO;
6970 }
6971 mutex_lock(&ipa3_ctx->lock);
6972 if (ipa3_ctx->ipa_initialization_complete) {
6973 mutex_unlock(&ipa3_ctx->lock);
6974 IPADBG("IPA driver finished initialization already\n");
6975 return -EEXIST;
6976 }
6977
6978 cb_info = kmalloc(sizeof(struct ipa3_ready_cb_info), GFP_KERNEL);
6979 if (!cb_info) {
6980 mutex_unlock(&ipa3_ctx->lock);
6981 return -ENOMEM;
6982 }
6983
6984 cb_info->ready_cb = ipa_ready_cb;
6985 cb_info->user_data = user_data;
6986
6987 list_add_tail(&cb_info->link, &ipa3_ctx->ipa_ready_cb_list);
6988 mutex_unlock(&ipa3_ctx->lock);
6989
6990 return 0;
6991}
6992
6993int ipa3_iommu_map(struct iommu_domain *domain,
6994 unsigned long iova, phys_addr_t paddr, size_t size, int prot)
6995{
Skylar Changefc0a0f2018-03-29 11:17:40 -07006996 struct ipa_smmu_cb_ctx *ap_cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
6997 struct ipa_smmu_cb_ctx *uc_cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC);
Amir Levy9659e592016-10-27 18:08:27 +03006998
6999 IPADBG("domain =0x%p iova 0x%lx\n", domain, iova);
7000 IPADBG("paddr =0x%pa size 0x%x\n", &paddr, (u32)size);
7001
7002 /* make sure no overlapping */
7003 if (domain == ipa3_get_smmu_domain()) {
7004 if (iova >= ap_cb->va_start && iova < ap_cb->va_end) {
7005 IPAERR("iommu AP overlap addr 0x%lx\n", iova);
7006 ipa_assert();
7007 return -EFAULT;
7008 }
7009 } else if (domain == ipa3_get_wlan_smmu_domain()) {
7010 /* wlan is one time map */
7011 } else if (domain == ipa3_get_uc_smmu_domain()) {
7012 if (iova >= uc_cb->va_start && iova < uc_cb->va_end) {
7013 IPAERR("iommu uC overlap addr 0x%lx\n", iova);
7014 ipa_assert();
7015 return -EFAULT;
7016 }
7017 } else {
7018 IPAERR("Unexpected domain 0x%p\n", domain);
7019 ipa_assert();
7020 return -EFAULT;
7021 }
7022
7023 return iommu_map(domain, iova, paddr, size, prot);
7024}
7025
Michael Adisumartad04e6d62017-11-09 17:46:35 -08007026/**
7027 * ipa3_get_smmu_params()- Return the ipa3 smmu related params.
7028 */
7029int ipa3_get_smmu_params(struct ipa_smmu_in_params *in,
7030 struct ipa_smmu_out_params *out)
7031{
7032 bool is_smmu_enable = 0;
7033
7034 if (out == NULL || in == NULL) {
7035 IPAERR("bad parms for Client SMMU out params\n");
7036 return -EINVAL;
7037 }
7038
7039 if (!ipa3_ctx) {
7040 IPAERR("IPA not yet initialized\n");
7041 return -EINVAL;
7042 }
7043
7044 switch (in->smmu_client) {
7045 case IPA_SMMU_WLAN_CLIENT:
7046 is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] |
7047 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN]);
7048 break;
7049 default:
7050 is_smmu_enable = 0;
7051 IPAERR("Trying to get illegal clients SMMU status");
7052 return -EINVAL;
7053 }
7054
7055 out->smmu_enable = is_smmu_enable;
7056
7057 return 0;
7058}
7059
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04007060/**************************************************************
7061 * PCIe Version
7062 *************************************************************/
7063
7064int ipa3_pci_drv_probe(
7065 struct pci_dev *pci_dev,
7066 struct ipa_api_controller *api_ctrl,
7067 const struct of_device_id *pdrv_match)
7068{
7069 int result;
7070 struct ipa3_plat_drv_res *ipa_drv_res;
7071 u32 bar0_offset;
7072 u32 mem_start;
7073 u32 mem_end;
7074 uint32_t bits;
7075 uint32_t ipa_start, gsi_start, intctrl_start;
7076 struct device *dev;
7077 static struct platform_device platform_dev;
7078
7079 if (!pci_dev || !api_ctrl || !pdrv_match) {
7080 IPAERR(
7081 "Bad arg: pci_dev (%pK) and/or api_ctrl (%pK) and/or pdrv_match (%pK)\n",
7082 pci_dev, api_ctrl, pdrv_match);
7083 return -EOPNOTSUPP;
7084 }
7085
7086 dev = &(pci_dev->dev);
7087
7088 IPADBG("IPA PCI driver probing started\n");
7089
7090 /*
7091 * Follow PCI driver flow here.
7092 * pci_enable_device: Enables device and assigns resources
7093 * pci_request_region: Makes BAR0 address region usable
7094 */
7095 result = pci_enable_device(pci_dev);
7096 if (result < 0) {
7097 IPAERR("pci_enable_device() failed\n");
7098 return -EOPNOTSUPP;
7099 }
7100
7101 result = pci_request_region(pci_dev, 0, "IPA Memory");
7102 if (result < 0) {
7103 IPAERR("pci_request_region() failed\n");
7104 pci_disable_device(pci_dev);
7105 return -EOPNOTSUPP;
7106 }
7107
7108 /*
7109 * When in the PCI/emulation environment, &platform_dev is
7110 * passed to get_ipa_dts_configuration(), but is unused, since
7111 * all usages of it in the function are replaced by CPP
7112 * relative to definitions in ipa_emulation_stubs.h. Passing
7113 * &platform_dev makes code validity tools happy.
7114 */
7115 if (get_ipa_dts_configuration(&platform_dev, &ipa3_res) != 0) {
7116 IPAERR("get_ipa_dts_configuration() failed\n");
7117 pci_release_region(pci_dev, 0);
7118 pci_disable_device(pci_dev);
7119 return -EOPNOTSUPP;
7120 }
7121
7122 ipa_drv_res = &ipa3_res;
7123
7124 result =
7125 of_property_read_u32(NULL, "emulator-bar0-offset",
7126 &bar0_offset);
7127 if (result) {
7128 IPAERR(":get resource failed for emulator-bar0-offset!\n");
7129 pci_release_region(pci_dev, 0);
7130 pci_disable_device(pci_dev);
7131 return -ENODEV;
7132 }
7133 IPADBG(":using emulator-bar0-offset 0x%08X\n", bar0_offset);
7134
7135 ipa_start = ipa_drv_res->ipa_mem_base;
7136 gsi_start = ipa_drv_res->transport_mem_base;
7137 intctrl_start = ipa_drv_res->emulator_intcntrlr_mem_base;
7138
7139 /*
7140 * Where will we be inerrupted at?
7141 */
7142 ipa_drv_res->emulator_irq = pci_dev->irq;
7143 IPADBG(
7144 "EMULATION PCI_INTERRUPT_PIN(%u)\n",
7145 ipa_drv_res->emulator_irq);
7146
7147 /*
7148 * Set the ipa_mem_base to the PCI base address of BAR0
7149 */
7150 mem_start = pci_resource_start(pci_dev, 0);
7151 mem_end = pci_resource_end(pci_dev, 0);
7152
7153 IPADBG("PCI START = 0x%x\n", mem_start);
7154 IPADBG("PCI END = 0x%x\n", mem_end);
7155
7156 ipa_drv_res->ipa_mem_base = mem_start + bar0_offset;
7157
7158 smmu_info.ipa_base = ipa_drv_res->ipa_mem_base;
7159 smmu_info.ipa_size = ipa_drv_res->ipa_mem_size;
7160
7161 ipa_drv_res->transport_mem_base =
7162 ipa_drv_res->ipa_mem_base + (gsi_start - ipa_start);
7163
7164 ipa_drv_res->emulator_intcntrlr_mem_base =
7165 ipa_drv_res->ipa_mem_base + (intctrl_start - ipa_start);
7166
7167 IPADBG("ipa_mem_base = 0x%x\n",
7168 ipa_drv_res->ipa_mem_base);
7169 IPADBG("ipa_mem_size = 0x%x\n",
7170 ipa_drv_res->ipa_mem_size);
7171
7172 IPADBG("transport_mem_base = 0x%x\n",
7173 ipa_drv_res->transport_mem_base);
7174 IPADBG("transport_mem_size = 0x%x\n",
7175 ipa_drv_res->transport_mem_size);
7176
7177 IPADBG("emulator_intcntrlr_mem_base = 0x%x\n",
7178 ipa_drv_res->emulator_intcntrlr_mem_base);
7179 IPADBG("emulator_intcntrlr_mem_size = 0x%x\n",
7180 ipa_drv_res->emulator_intcntrlr_mem_size);
7181
7182 result = ipa3_bind_api_controller(ipa_drv_res->ipa_hw_type, api_ctrl);
7183 if (result != 0) {
7184 IPAERR("ipa3_bind_api_controller() failed\n");
7185 pci_release_region(pci_dev, 0);
7186 pci_disable_device(pci_dev);
7187 return result;
7188 }
7189
7190 bits = (ipa_drv_res->use_64_bit_dma_mask) ? 64 : 32;
7191
7192 if (dma_set_mask(dev, DMA_BIT_MASK(bits)) != 0) {
7193 IPAERR("dma_set_mask(%pK, %u) failed\n", dev, bits);
7194 pci_release_region(pci_dev, 0);
7195 pci_disable_device(pci_dev);
7196 return -EOPNOTSUPP;
7197 }
7198
7199 if (dma_set_coherent_mask(dev, DMA_BIT_MASK(bits)) != 0) {
7200 IPAERR("dma_set_coherent_mask(%pK, %u) failed\n", dev, bits);
7201 pci_release_region(pci_dev, 0);
7202 pci_disable_device(pci_dev);
7203 return -EOPNOTSUPP;
7204 }
7205
7206 pci_set_master(pci_dev);
7207
7208 memset(&platform_dev, 0, sizeof(platform_dev));
7209 platform_dev.dev = *dev;
7210
7211 /* Proceed to real initialization */
7212 result = ipa3_pre_init(&ipa3_res, &platform_dev);
7213 if (result) {
7214 IPAERR("ipa3_init failed\n");
7215 pci_clear_master(pci_dev);
7216 pci_release_region(pci_dev, 0);
7217 pci_disable_device(pci_dev);
7218 return result;
7219 }
7220
7221 return result;
7222}
7223
7224/*
7225 * The following returns transport register memory location and
7226 * size...
7227 */
7228int ipa3_get_transport_info(
7229 phys_addr_t *phys_addr_ptr,
7230 unsigned long *size_ptr)
7231{
7232 if (!phys_addr_ptr || !size_ptr) {
7233 IPAERR("Bad arg: phys_addr_ptr(%pK) and/or size_ptr(%pK)\n",
7234 phys_addr_ptr, size_ptr);
7235 return -EINVAL;
7236 }
7237
7238 *phys_addr_ptr = ipa3_res.transport_mem_base;
7239 *size_ptr = ipa3_res.transport_mem_size;
7240
7241 return 0;
7242}
7243EXPORT_SYMBOL(ipa3_get_transport_info);
7244
7245static uint emulation_type = IPA_HW_v4_0;
7246
7247/*
7248 * The following returns emulation type...
7249 */
7250uint ipa3_get_emulation_type(void)
7251{
7252 return emulation_type;
7253}
7254
Amir Levy9659e592016-10-27 18:08:27 +03007255MODULE_LICENSE("GPL v2");
7256MODULE_DESCRIPTION("IPA HW device driver");
Jennifer L. Zennerdf159af2018-04-25 16:44:38 -04007257
7258/*
7259 * Module parameter. Invoke as follows:
7260 * insmod ipat.ko emulation_type=[13|14|...|N]
7261 * Examples:
7262 * insmod ipat.ko emulation_type=13 # for IPA 3.5.1
7263 * insmod ipat.ko emulation_type=14 # for IPA 4.0
7264 *
7265 * NOTE: The emulation_type values need to come from: enum ipa_hw_type
7266 *
7267 */
7268
7269module_param(emulation_type, uint, 0000);
7270MODULE_PARM_DESC(
7271 emulation_type,
7272 "IPA emulation type (Use 13 for IPA 3.5.1, 14 for IPA 4.0)");