blob: af926fb9498f9acc5ca0cb855ce1c0b9b1d05460 [file] [log] [blame]
Michael Adisumartad8c88e52018-01-05 10:22:38 -08001/* Copyright (c) 2012-2018, 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>
Amir Levy9659e592016-10-27 18:08:27 +030038#include <soc/qcom/subsystem_restart.h>
39#include <soc/qcom/smem.h>
Gidon Studinski3021a6f2016-11-10 12:48:48 +020040#include <soc/qcom/scm.h>
Amir Levy635bced2016-12-19 09:20:42 +020041#include <asm/cacheflush.h>
Gidon Studinski3021a6f2016-11-10 12:48:48 +020042
43#ifdef CONFIG_ARM64
44
45/* Outer caches unsupported on ARM64 platforms */
46#define outer_flush_range(x, y)
47#define __cpuc_flush_dcache_area __flush_dcache_area
48
49#endif
50
Amir Levy9659e592016-10-27 18:08:27 +030051#define IPA_SUBSYSTEM_NAME "ipa_fws"
52#include "ipa_i.h"
53#include "../ipa_rm_i.h"
54#include "ipahal/ipahal.h"
55#include "ipahal/ipahal_fltrt.h"
56
57#define CREATE_TRACE_POINTS
58#include "ipa_trace.h"
59
60#define IPA_GPIO_IN_QUERY_CLK_IDX 0
61#define IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX 0
62#define IPA_GPIO_OUT_CLK_VOTE_IDX 1
63
64#define IPA_SUMMING_THRESHOLD (0x10)
65#define IPA_PIPE_MEM_START_OFST (0x0)
66#define IPA_PIPE_MEM_SIZE (0x0)
67#define IPA_MOBILE_AP_MODE(x) (x == IPA_MODE_MOBILE_AP_ETH || \
68 x == IPA_MODE_MOBILE_AP_WAN || \
69 x == IPA_MODE_MOBILE_AP_WLAN)
70#define IPA_CNOC_CLK_RATE (75 * 1000 * 1000UL)
71#define IPA_A5_MUX_HEADER_LENGTH (8)
72
73#define IPA_AGGR_MAX_STR_LENGTH (10)
74
Gidon Studinski3021a6f2016-11-10 12:48:48 +020075#define CLEANUP_TAG_PROCESS_TIMEOUT 500
Amir Levy9659e592016-10-27 18:08:27 +030076
77#define IPA_AGGR_STR_IN_BYTES(str) \
78 (strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1)
79
80#define IPA_TRANSPORT_PROD_TIMEOUT_MSEC 100
81
82#define IPA3_ACTIVE_CLIENTS_TABLE_BUF_SIZE 2048
83
84#define IPA3_ACTIVE_CLIENT_LOG_TYPE_EP 0
85#define IPA3_ACTIVE_CLIENT_LOG_TYPE_SIMPLE 1
86#define IPA3_ACTIVE_CLIENT_LOG_TYPE_RESOURCE 2
87#define IPA3_ACTIVE_CLIENT_LOG_TYPE_SPECIAL 3
88
Ghanim Fodic823bc62017-10-21 17:29:53 +030089#define IPA_MHI_GSI_EVENT_RING_ID_START 10
90#define IPA_MHI_GSI_EVENT_RING_ID_END 12
91
Amir Levy9659e592016-10-27 18:08:27 +030092#define IPA_SMEM_SIZE (8 * 1024)
93
Michael Adisumartaf01e9fd2017-08-31 12:23:51 -070094#define IPA_GSI_CHANNEL_HALT_MIN_SLEEP 5000
95#define IPA_GSI_CHANNEL_HALT_MAX_SLEEP 10000
96#define IPA_GSI_CHANNEL_HALT_MAX_TRY 10
97
Amir Levy9659e592016-10-27 18:08:27 +030098/* round addresses for closes page per SMMU requirements */
99#define IPA_SMMU_ROUND_TO_PAGE(iova, pa, size, iova_p, pa_p, size_p) \
100 do { \
101 (iova_p) = rounddown((iova), PAGE_SIZE); \
102 (pa_p) = rounddown((pa), PAGE_SIZE); \
103 (size_p) = roundup((size) + (pa) - (pa_p), PAGE_SIZE); \
104 } while (0)
105
106
107/* The relative location in /lib/firmware where the FWs will reside */
108#define IPA_FWS_PATH "ipa/ipa_fws.elf"
109
110#ifdef CONFIG_COMPAT
111#define IPA_IOC_ADD_HDR32 _IOWR(IPA_IOC_MAGIC, \
112 IPA_IOCTL_ADD_HDR, \
113 compat_uptr_t)
114#define IPA_IOC_DEL_HDR32 _IOWR(IPA_IOC_MAGIC, \
115 IPA_IOCTL_DEL_HDR, \
116 compat_uptr_t)
117#define IPA_IOC_ADD_RT_RULE32 _IOWR(IPA_IOC_MAGIC, \
118 IPA_IOCTL_ADD_RT_RULE, \
119 compat_uptr_t)
120#define IPA_IOC_DEL_RT_RULE32 _IOWR(IPA_IOC_MAGIC, \
121 IPA_IOCTL_DEL_RT_RULE, \
122 compat_uptr_t)
123#define IPA_IOC_ADD_FLT_RULE32 _IOWR(IPA_IOC_MAGIC, \
124 IPA_IOCTL_ADD_FLT_RULE, \
125 compat_uptr_t)
126#define IPA_IOC_DEL_FLT_RULE32 _IOWR(IPA_IOC_MAGIC, \
127 IPA_IOCTL_DEL_FLT_RULE, \
128 compat_uptr_t)
129#define IPA_IOC_GET_RT_TBL32 _IOWR(IPA_IOC_MAGIC, \
130 IPA_IOCTL_GET_RT_TBL, \
131 compat_uptr_t)
132#define IPA_IOC_COPY_HDR32 _IOWR(IPA_IOC_MAGIC, \
133 IPA_IOCTL_COPY_HDR, \
134 compat_uptr_t)
135#define IPA_IOC_QUERY_INTF32 _IOWR(IPA_IOC_MAGIC, \
136 IPA_IOCTL_QUERY_INTF, \
137 compat_uptr_t)
138#define IPA_IOC_QUERY_INTF_TX_PROPS32 _IOWR(IPA_IOC_MAGIC, \
139 IPA_IOCTL_QUERY_INTF_TX_PROPS, \
140 compat_uptr_t)
141#define IPA_IOC_QUERY_INTF_RX_PROPS32 _IOWR(IPA_IOC_MAGIC, \
142 IPA_IOCTL_QUERY_INTF_RX_PROPS, \
143 compat_uptr_t)
144#define IPA_IOC_QUERY_INTF_EXT_PROPS32 _IOWR(IPA_IOC_MAGIC, \
145 IPA_IOCTL_QUERY_INTF_EXT_PROPS, \
146 compat_uptr_t)
147#define IPA_IOC_GET_HDR32 _IOWR(IPA_IOC_MAGIC, \
148 IPA_IOCTL_GET_HDR, \
149 compat_uptr_t)
150#define IPA_IOC_ALLOC_NAT_MEM32 _IOWR(IPA_IOC_MAGIC, \
151 IPA_IOCTL_ALLOC_NAT_MEM, \
152 compat_uptr_t)
Amir Levy479cfdd2017-10-26 12:23:14 +0300153#define IPA_IOC_ALLOC_NAT_TABLE32 _IOWR(IPA_IOC_MAGIC, \
154 IPA_IOCTL_ALLOC_NAT_TABLE, \
155 compat_uptr_t)
156#define IPA_IOC_ALLOC_IPV6CT_TABLE32 _IOWR(IPA_IOC_MAGIC, \
157 IPA_IOCTL_ALLOC_IPV6CT_TABLE, \
158 compat_uptr_t)
Amir Levy9659e592016-10-27 18:08:27 +0300159#define IPA_IOC_V4_INIT_NAT32 _IOWR(IPA_IOC_MAGIC, \
160 IPA_IOCTL_V4_INIT_NAT, \
161 compat_uptr_t)
Amir Levy479cfdd2017-10-26 12:23:14 +0300162#define IPA_IOC_INIT_IPV6CT_TABLE32 _IOWR(IPA_IOC_MAGIC, \
163 IPA_IOCTL_INIT_IPV6CT_TABLE, \
164 compat_uptr_t)
165#define IPA_IOC_TABLE_DMA_CMD32 _IOWR(IPA_IOC_MAGIC, \
166 IPA_IOCTL_TABLE_DMA_CMD, \
Amir Levy9659e592016-10-27 18:08:27 +0300167 compat_uptr_t)
168#define IPA_IOC_V4_DEL_NAT32 _IOWR(IPA_IOC_MAGIC, \
169 IPA_IOCTL_V4_DEL_NAT, \
170 compat_uptr_t)
Amir Levy479cfdd2017-10-26 12:23:14 +0300171#define IPA_IOC_DEL_NAT_TABLE32 _IOWR(IPA_IOC_MAGIC, \
172 IPA_IOCTL_DEL_NAT_TABLE, \
173 compat_uptr_t)
174#define IPA_IOC_DEL_IPV6CT_TABLE32 _IOWR(IPA_IOC_MAGIC, \
175 IPA_IOCTL_DEL_IPV6CT_TABLE, \
176 compat_uptr_t)
177#define IPA_IOC_NAT_MODIFY_PDN32 _IOWR(IPA_IOC_MAGIC, \
178 IPA_IOCTL_NAT_MODIFY_PDN, \
179 compat_uptr_t)
Amir Levy9659e592016-10-27 18:08:27 +0300180#define IPA_IOC_GET_NAT_OFFSET32 _IOWR(IPA_IOC_MAGIC, \
181 IPA_IOCTL_GET_NAT_OFFSET, \
182 compat_uptr_t)
183#define IPA_IOC_PULL_MSG32 _IOWR(IPA_IOC_MAGIC, \
184 IPA_IOCTL_PULL_MSG, \
185 compat_uptr_t)
186#define IPA_IOC_RM_ADD_DEPENDENCY32 _IOWR(IPA_IOC_MAGIC, \
187 IPA_IOCTL_RM_ADD_DEPENDENCY, \
188 compat_uptr_t)
189#define IPA_IOC_RM_DEL_DEPENDENCY32 _IOWR(IPA_IOC_MAGIC, \
190 IPA_IOCTL_RM_DEL_DEPENDENCY, \
191 compat_uptr_t)
192#define IPA_IOC_GENERATE_FLT_EQ32 _IOWR(IPA_IOC_MAGIC, \
193 IPA_IOCTL_GENERATE_FLT_EQ, \
194 compat_uptr_t)
195#define IPA_IOC_QUERY_RT_TBL_INDEX32 _IOWR(IPA_IOC_MAGIC, \
196 IPA_IOCTL_QUERY_RT_TBL_INDEX, \
197 compat_uptr_t)
198#define IPA_IOC_WRITE_QMAPID32 _IOWR(IPA_IOC_MAGIC, \
199 IPA_IOCTL_WRITE_QMAPID, \
200 compat_uptr_t)
201#define IPA_IOC_MDFY_FLT_RULE32 _IOWR(IPA_IOC_MAGIC, \
202 IPA_IOCTL_MDFY_FLT_RULE, \
203 compat_uptr_t)
204#define IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD32 _IOWR(IPA_IOC_MAGIC, \
205 IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_ADD, \
206 compat_uptr_t)
207#define IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL32 _IOWR(IPA_IOC_MAGIC, \
208 IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_DEL, \
209 compat_uptr_t)
210#define IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED32 _IOWR(IPA_IOC_MAGIC, \
211 IPA_IOCTL_NOTIFY_WAN_EMBMS_CONNECTED, \
212 compat_uptr_t)
213#define IPA_IOC_ADD_HDR_PROC_CTX32 _IOWR(IPA_IOC_MAGIC, \
214 IPA_IOCTL_ADD_HDR_PROC_CTX, \
215 compat_uptr_t)
216#define IPA_IOC_DEL_HDR_PROC_CTX32 _IOWR(IPA_IOC_MAGIC, \
217 IPA_IOCTL_DEL_HDR_PROC_CTX, \
218 compat_uptr_t)
219#define IPA_IOC_MDFY_RT_RULE32 _IOWR(IPA_IOC_MAGIC, \
220 IPA_IOCTL_MDFY_RT_RULE, \
221 compat_uptr_t)
222
223/**
224 * struct ipa3_ioc_nat_alloc_mem32 - nat table memory allocation
225 * properties
226 * @dev_name: input parameter, the name of table
227 * @size: input parameter, size of table in bytes
228 * @offset: output parameter, offset into page in case of system memory
229 */
230struct ipa3_ioc_nat_alloc_mem32 {
231 char dev_name[IPA_RESOURCE_NAME_MAX];
232 compat_size_t size;
233 compat_off_t offset;
234};
Amir Levy479cfdd2017-10-26 12:23:14 +0300235
236/**
237 * struct ipa_ioc_nat_ipv6ct_table_alloc32 - table memory allocation
238 * properties
239 * @size: input parameter, size of table in bytes
240 * @offset: output parameter, offset into page in case of system memory
241 */
242struct ipa_ioc_nat_ipv6ct_table_alloc32 {
243 compat_size_t size;
244 compat_off_t offset;
245};
246
Amir Levy9659e592016-10-27 18:08:27 +0300247#endif
248
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200249#define IPA_TZ_UNLOCK_ATTRIBUTE 0x0C0311
250#define TZ_MEM_PROTECT_REGION_ID 0x10
251
252struct tz_smmu_ipa_protect_region_iovec_s {
253 u64 input_addr;
254 u64 output_addr;
255 u64 size;
256 u32 attr;
257} __packed;
258
259struct tz_smmu_ipa_protect_region_s {
260 phys_addr_t iovec_buf;
261 u32 size_bytes;
262} __packed;
263
Amir Levy9659e592016-10-27 18:08:27 +0300264static void ipa3_start_tag_process(struct work_struct *work);
265static DECLARE_WORK(ipa3_tag_work, ipa3_start_tag_process);
266
Amir Levya59ed3f2017-03-05 17:30:55 +0200267static void ipa3_transport_release_resource(struct work_struct *work);
268static DECLARE_DELAYED_WORK(ipa3_transport_release_resource_work,
269 ipa3_transport_release_resource);
Amir Levy9659e592016-10-27 18:08:27 +0300270static void ipa_gsi_notify_cb(struct gsi_per_notify *notify);
271
Skylar Changefc0a0f2018-03-29 11:17:40 -0700272static int ipa3_attach_to_smmu(void);
273static int ipa3_alloc_pkt_init(void);
274
Ghanim Fodia5f376a2017-10-17 18:14:53 +0300275static void ipa3_load_ipa_fw(struct work_struct *work);
276static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw);
Utkarsh Saxenaded78142017-05-03 14:04:30 +0530277
Skylar Chang242952b2017-07-20 15:04:05 -0700278static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work);
279static DECLARE_WORK(ipa_dec_clients_disable_clks_on_wq_work,
280 ipa_dec_clients_disable_clks_on_wq);
281
Amir Levy9659e592016-10-27 18:08:27 +0300282static struct ipa3_plat_drv_res ipa3_res = {0, };
Amir Levy9659e592016-10-27 18:08:27 +0300283
284static struct clk *ipa3_clk;
285
286struct ipa3_context *ipa3_ctx;
Amir Levy9659e592016-10-27 18:08:27 +0300287static struct {
Skylar Changefc0a0f2018-03-29 11:17:40 -0700288 bool present[IPA_SMMU_CB_MAX];
Amir Levy9659e592016-10-27 18:08:27 +0300289 bool arm_smmu;
Amir Levy9659e592016-10-27 18:08:27 +0300290 bool fast_map;
Michael Adisumarta93e97522017-10-06 15:49:46 -0700291 bool s1_bypass_arr[IPA_SMMU_CB_MAX];
Amir Levy9659e592016-10-27 18:08:27 +0300292 bool use_64_bit_dma_mask;
293 u32 ipa_base;
294 u32 ipa_size;
295} smmu_info;
296
297static char *active_clients_table_buf;
298
299int ipa3_active_clients_log_print_buffer(char *buf, int size)
300{
301 int i;
302 int nbytes;
303 int cnt = 0;
304 int start_idx;
305 int end_idx;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700306 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +0300307
Skylar Chang69ae50e2017-07-31 13:13:29 -0700308 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300309 start_idx = (ipa3_ctx->ipa3_active_clients_logging.log_tail + 1) %
310 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES;
311 end_idx = ipa3_ctx->ipa3_active_clients_logging.log_head;
312 for (i = start_idx; i != end_idx;
313 i = (i + 1) % IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) {
314 nbytes = scnprintf(buf + cnt, size - cnt, "%s\n",
315 ipa3_ctx->ipa3_active_clients_logging
316 .log_buffer[i]);
317 cnt += nbytes;
318 }
Skylar Chang69ae50e2017-07-31 13:13:29 -0700319 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
320 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300321
322 return cnt;
323}
324
325int ipa3_active_clients_log_print_table(char *buf, int size)
326{
327 int i;
328 struct ipa3_active_client_htable_entry *iterator;
329 int cnt = 0;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700330 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +0300331
Skylar Chang69ae50e2017-07-31 13:13:29 -0700332 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300333 cnt = scnprintf(buf, size, "\n---- Active Clients Table ----\n");
334 hash_for_each(ipa3_ctx->ipa3_active_clients_logging.htable, i,
335 iterator, list) {
336 switch (iterator->type) {
337 case IPA3_ACTIVE_CLIENT_LOG_TYPE_EP:
338 cnt += scnprintf(buf + cnt, size - cnt,
339 "%-40s %-3d ENDPOINT\n",
340 iterator->id_string, iterator->count);
341 break;
342 case IPA3_ACTIVE_CLIENT_LOG_TYPE_SIMPLE:
343 cnt += scnprintf(buf + cnt, size - cnt,
344 "%-40s %-3d SIMPLE\n",
345 iterator->id_string, iterator->count);
346 break;
347 case IPA3_ACTIVE_CLIENT_LOG_TYPE_RESOURCE:
348 cnt += scnprintf(buf + cnt, size - cnt,
349 "%-40s %-3d RESOURCE\n",
350 iterator->id_string, iterator->count);
351 break;
352 case IPA3_ACTIVE_CLIENT_LOG_TYPE_SPECIAL:
353 cnt += scnprintf(buf + cnt, size - cnt,
354 "%-40s %-3d SPECIAL\n",
355 iterator->id_string, iterator->count);
356 break;
357 default:
358 IPAERR("Trying to print illegal active_clients type");
359 break;
360 }
361 }
362 cnt += scnprintf(buf + cnt, size - cnt,
363 "\nTotal active clients count: %d\n",
Skylar Chang242952b2017-07-20 15:04:05 -0700364 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
Skylar Chang69ae50e2017-07-31 13:13:29 -0700365 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
366 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300367
368 return cnt;
369}
370
Skylar Chang68c37d82018-04-07 16:42:36 -0700371static int ipa3_clean_modem_rule(void)
372{
373 struct ipa_install_fltr_rule_req_msg_v01 *req;
374 struct ipa_install_fltr_rule_req_ex_msg_v01 *req_ex;
375 int val = 0;
376
377 if (ipa3_ctx->ipa_hw_type < IPA_HW_v3_0) {
378 req = kzalloc(
379 sizeof(struct ipa_install_fltr_rule_req_msg_v01),
380 GFP_KERNEL);
381 if (!req) {
382 IPAERR("mem allocated failed!\n");
383 return -ENOMEM;
384 }
385 req->filter_spec_list_valid = false;
386 req->filter_spec_list_len = 0;
387 req->source_pipe_index_valid = 0;
388 val = ipa3_qmi_filter_request_send(req);
389 kfree(req);
390 } else {
391 req_ex = kzalloc(
392 sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01),
393 GFP_KERNEL);
394 if (!req_ex) {
395 IPAERR("mem allocated failed!\n");
396 return -ENOMEM;
397 }
398 req_ex->filter_spec_ex_list_valid = false;
399 req_ex->filter_spec_ex_list_len = 0;
400 req_ex->source_pipe_index_valid = 0;
401 val = ipa3_qmi_filter_request_ex_send(req_ex);
402 kfree(req_ex);
403 }
404
405 return val;
406}
407
Amir Levy9659e592016-10-27 18:08:27 +0300408static int ipa3_active_clients_panic_notifier(struct notifier_block *this,
409 unsigned long event, void *ptr)
410{
Amir Levy9659e592016-10-27 18:08:27 +0300411 ipa3_active_clients_log_print_table(active_clients_table_buf,
412 IPA3_ACTIVE_CLIENTS_TABLE_BUF_SIZE);
Michael Adisumartaedba22d2018-04-19 12:28:33 -0700413 IPAERR("%s\n", active_clients_table_buf);
Amir Levy9659e592016-10-27 18:08:27 +0300414
415 return NOTIFY_DONE;
416}
417
418static struct notifier_block ipa3_active_clients_panic_blk = {
419 .notifier_call = ipa3_active_clients_panic_notifier,
420};
421
422static int ipa3_active_clients_log_insert(const char *string)
423{
424 int head;
425 int tail;
426
427 if (!ipa3_ctx->ipa3_active_clients_logging.log_rdy)
428 return -EPERM;
429
430 head = ipa3_ctx->ipa3_active_clients_logging.log_head;
431 tail = ipa3_ctx->ipa3_active_clients_logging.log_tail;
432
433 memset(ipa3_ctx->ipa3_active_clients_logging.log_buffer[head], '_',
434 IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN);
435 strlcpy(ipa3_ctx->ipa3_active_clients_logging.log_buffer[head], string,
436 (size_t)IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN);
437 head = (head + 1) % IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES;
438 if (tail == head)
439 tail = (tail + 1) % IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES;
440
441 ipa3_ctx->ipa3_active_clients_logging.log_tail = tail;
442 ipa3_ctx->ipa3_active_clients_logging.log_head = head;
443
444 return 0;
445}
446
447static int ipa3_active_clients_log_init(void)
448{
449 int i;
450
Skylar Chang69ae50e2017-07-31 13:13:29 -0700451 spin_lock_init(&ipa3_ctx->ipa3_active_clients_logging.lock);
Amir Levy9659e592016-10-27 18:08:27 +0300452 ipa3_ctx->ipa3_active_clients_logging.log_buffer[0] = kzalloc(
453 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES *
454 sizeof(char[IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN]),
455 GFP_KERNEL);
456 active_clients_table_buf = kzalloc(sizeof(
457 char[IPA3_ACTIVE_CLIENTS_TABLE_BUF_SIZE]), GFP_KERNEL);
458 if (ipa3_ctx->ipa3_active_clients_logging.log_buffer == NULL) {
459 pr_err("Active Clients Logging memory allocation failed");
460 goto bail;
461 }
462 for (i = 0; i < IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; i++) {
463 ipa3_ctx->ipa3_active_clients_logging.log_buffer[i] =
464 ipa3_ctx->ipa3_active_clients_logging.log_buffer[0] +
465 (IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN * i);
466 }
467 ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
468 ipa3_ctx->ipa3_active_clients_logging.log_tail =
469 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
470 hash_init(ipa3_ctx->ipa3_active_clients_logging.htable);
471 atomic_notifier_chain_register(&panic_notifier_list,
472 &ipa3_active_clients_panic_blk);
473 ipa3_ctx->ipa3_active_clients_logging.log_rdy = 1;
474
475 return 0;
476
477bail:
478 return -ENOMEM;
479}
480
481void ipa3_active_clients_log_clear(void)
482{
Skylar Chang69ae50e2017-07-31 13:13:29 -0700483 unsigned long flags;
484
485 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300486 ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
487 ipa3_ctx->ipa3_active_clients_logging.log_tail =
488 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700489 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
490 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300491}
492
493static void ipa3_active_clients_log_destroy(void)
494{
Skylar Chang69ae50e2017-07-31 13:13:29 -0700495 unsigned long flags;
496
497 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300498 ipa3_ctx->ipa3_active_clients_logging.log_rdy = 0;
Ghanim Fodic48ba992017-12-24 19:28:38 +0200499 kfree(active_clients_table_buf);
500 active_clients_table_buf = NULL;
Amir Levy9659e592016-10-27 18:08:27 +0300501 kfree(ipa3_ctx->ipa3_active_clients_logging.log_buffer[0]);
502 ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
503 ipa3_ctx->ipa3_active_clients_logging.log_tail =
504 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700505 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
506 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300507}
508
Amir Levy9659e592016-10-27 18:08:27 +0300509static struct ipa_smmu_cb_ctx smmu_cb[IPA_SMMU_CB_MAX];
510
511struct iommu_domain *ipa3_get_smmu_domain(void)
512{
513 if (smmu_cb[IPA_SMMU_CB_AP].valid)
514 return smmu_cb[IPA_SMMU_CB_AP].mapping->domain;
515
516 IPAERR("CB not valid\n");
517
518 return NULL;
519}
520
521struct iommu_domain *ipa3_get_uc_smmu_domain(void)
522{
523 if (smmu_cb[IPA_SMMU_CB_UC].valid)
524 return smmu_cb[IPA_SMMU_CB_UC].mapping->domain;
525
526 IPAERR("CB not valid\n");
527
528 return NULL;
529}
530
531struct iommu_domain *ipa3_get_wlan_smmu_domain(void)
532{
533 if (smmu_cb[IPA_SMMU_CB_WLAN].valid)
534 return smmu_cb[IPA_SMMU_CB_WLAN].iommu;
535
536 IPAERR("CB not valid\n");
537
538 return NULL;
539}
540
Michael Adisumartab1bafa42018-04-16 16:48:10 -0700541struct iommu_domain *ipa3_get_smmu_domain_by_type(enum ipa_smmu_cb_type cb_type)
542{
543
544 if (cb_type == IPA_SMMU_CB_WLAN && smmu_cb[IPA_SMMU_CB_WLAN].valid)
545 return smmu_cb[IPA_SMMU_CB_WLAN].iommu;
546
547 if (smmu_cb[cb_type].valid)
548 return smmu_cb[cb_type].mapping->domain;
549
550 IPAERR("CB#%d not valid\n", cb_type);
551
552 return NULL;
553}
Amir Levy9659e592016-10-27 18:08:27 +0300554
555struct device *ipa3_get_dma_dev(void)
556{
557 return ipa3_ctx->pdev;
558}
559
560/**
Skylar Changefc0a0f2018-03-29 11:17:40 -0700561 * ipa3_get_smmu_ctx()- Return smmu context for the given cb_type
Amir Levy9659e592016-10-27 18:08:27 +0300562 *
563 * Return value: pointer to smmu context address
564 */
Skylar Changefc0a0f2018-03-29 11:17:40 -0700565struct ipa_smmu_cb_ctx *ipa3_get_smmu_ctx(enum ipa_smmu_cb_type cb_type)
Amir Levy9659e592016-10-27 18:08:27 +0300566{
Skylar Changefc0a0f2018-03-29 11:17:40 -0700567 return &smmu_cb[cb_type];
Amir Levy9659e592016-10-27 18:08:27 +0300568}
569
570static int ipa3_open(struct inode *inode, struct file *filp)
571{
Amir Levy9659e592016-10-27 18:08:27 +0300572 IPADBG_LOW("ENTER\n");
Skylar Changefc0a0f2018-03-29 11:17:40 -0700573 filp->private_data = ipa3_ctx;
Amir Levy9659e592016-10-27 18:08:27 +0300574
575 return 0;
576}
577
Amir Levy9659e592016-10-27 18:08:27 +0300578static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type)
579{
580 if (!buff) {
581 IPAERR("Null buffer\n");
582 return;
583 }
584
585 if (type != WAN_UPSTREAM_ROUTE_ADD &&
586 type != WAN_UPSTREAM_ROUTE_DEL &&
587 type != WAN_EMBMS_CONNECT) {
588 IPAERR("Wrong type given. buff %p type %d\n", buff, type);
589 return;
590 }
591
592 kfree(buff);
593}
594
Skylar Chang68c37d82018-04-07 16:42:36 -0700595static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type,
596 bool is_cache)
Amir Levy9659e592016-10-27 18:08:27 +0300597{
598 int retval;
599 struct ipa_wan_msg *wan_msg;
600 struct ipa_msg_meta msg_meta;
Mohammed Javid616bb992017-10-03 13:10:05 +0530601 struct ipa_wan_msg cache_wan_msg;
Amir Levy9659e592016-10-27 18:08:27 +0300602
603 wan_msg = kzalloc(sizeof(struct ipa_wan_msg), GFP_KERNEL);
604 if (!wan_msg) {
605 IPAERR("no memory\n");
606 return -ENOMEM;
607 }
608
Amir Levy479cfdd2017-10-26 12:23:14 +0300609 if (copy_from_user(wan_msg, (const void __user *)usr_param,
Amir Levy9659e592016-10-27 18:08:27 +0300610 sizeof(struct ipa_wan_msg))) {
611 kfree(wan_msg);
612 return -EFAULT;
613 }
614
Mohammed Javid616bb992017-10-03 13:10:05 +0530615 memcpy(&cache_wan_msg, wan_msg, sizeof(cache_wan_msg));
616
Amir Levy9659e592016-10-27 18:08:27 +0300617 memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
618 msg_meta.msg_type = msg_type;
619 msg_meta.msg_len = sizeof(struct ipa_wan_msg);
620 retval = ipa3_send_msg(&msg_meta, wan_msg, ipa3_wan_msg_free_cb);
621 if (retval) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530622 IPAERR_RL("ipa3_send_msg failed: %d\n", retval);
Amir Levy9659e592016-10-27 18:08:27 +0300623 kfree(wan_msg);
624 return retval;
625 }
626
Mohammed Javidb4b5ef42017-08-29 01:05:46 +0530627 if (is_cache) {
628 mutex_lock(&ipa3_ctx->ipa_cne_evt_lock);
629
630 /* cache the cne event */
631 memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[
632 ipa3_ctx->num_ipa_cne_evt_req].wan_msg,
Mohammed Javid616bb992017-10-03 13:10:05 +0530633 &cache_wan_msg,
634 sizeof(cache_wan_msg));
Mohammed Javidb4b5ef42017-08-29 01:05:46 +0530635
636 memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[
637 ipa3_ctx->num_ipa_cne_evt_req].msg_meta,
638 &msg_meta,
639 sizeof(struct ipa_msg_meta));
640
641 ipa3_ctx->num_ipa_cne_evt_req++;
642 ipa3_ctx->num_ipa_cne_evt_req %= IPA_MAX_NUM_REQ_CACHE;
643 mutex_unlock(&ipa3_ctx->ipa_cne_evt_lock);
644 }
645
Amir Levy9659e592016-10-27 18:08:27 +0300646 return 0;
647}
648
Shihuan Liuc3174f52017-05-04 15:59:13 -0700649static void ipa3_vlan_l2tp_msg_free_cb(void *buff, u32 len, u32 type)
650{
651 if (!buff) {
652 IPAERR("Null buffer\n");
653 return;
654 }
655
656 if (type != ADD_VLAN_IFACE &&
657 type != DEL_VLAN_IFACE &&
658 type != ADD_L2TP_VLAN_MAPPING &&
659 type != DEL_L2TP_VLAN_MAPPING) {
660 IPAERR("Wrong type given. buff %pK type %d\n", buff, type);
661 return;
662 }
663
664 kfree(buff);
665}
666
667static int ipa3_send_vlan_l2tp_msg(unsigned long usr_param, uint8_t msg_type)
668{
669 int retval;
670 struct ipa_ioc_vlan_iface_info *vlan_info;
671 struct ipa_ioc_l2tp_vlan_mapping_info *mapping_info;
672 struct ipa_msg_meta msg_meta;
673
674 if (msg_type == ADD_VLAN_IFACE ||
675 msg_type == DEL_VLAN_IFACE) {
676 vlan_info = kzalloc(sizeof(struct ipa_ioc_vlan_iface_info),
677 GFP_KERNEL);
678 if (!vlan_info) {
679 IPAERR("no memory\n");
680 return -ENOMEM;
681 }
682
683 if (copy_from_user((u8 *)vlan_info, (void __user *)usr_param,
684 sizeof(struct ipa_ioc_vlan_iface_info))) {
685 kfree(vlan_info);
686 return -EFAULT;
687 }
688
689 memset(&msg_meta, 0, sizeof(msg_meta));
690 msg_meta.msg_type = msg_type;
691 msg_meta.msg_len = sizeof(struct ipa_ioc_vlan_iface_info);
692 retval = ipa3_send_msg(&msg_meta, vlan_info,
693 ipa3_vlan_l2tp_msg_free_cb);
694 if (retval) {
695 IPAERR("ipa3_send_msg failed: %d\n", retval);
696 kfree(vlan_info);
697 return retval;
698 }
699 } else if (msg_type == ADD_L2TP_VLAN_MAPPING ||
700 msg_type == DEL_L2TP_VLAN_MAPPING) {
701 mapping_info = kzalloc(sizeof(struct
702 ipa_ioc_l2tp_vlan_mapping_info), GFP_KERNEL);
703 if (!mapping_info) {
704 IPAERR("no memory\n");
705 return -ENOMEM;
706 }
707
708 if (copy_from_user((u8 *)mapping_info,
709 (void __user *)usr_param,
710 sizeof(struct ipa_ioc_l2tp_vlan_mapping_info))) {
711 kfree(mapping_info);
712 return -EFAULT;
713 }
714
715 memset(&msg_meta, 0, sizeof(msg_meta));
716 msg_meta.msg_type = msg_type;
717 msg_meta.msg_len = sizeof(struct
718 ipa_ioc_l2tp_vlan_mapping_info);
719 retval = ipa3_send_msg(&msg_meta, mapping_info,
720 ipa3_vlan_l2tp_msg_free_cb);
721 if (retval) {
722 IPAERR("ipa3_send_msg failed: %d\n", retval);
723 kfree(mapping_info);
724 return retval;
725 }
726 } else {
727 IPAERR("Unexpected event\n");
728 return -EFAULT;
729 }
730
731 return 0;
732}
Amir Levy9659e592016-10-27 18:08:27 +0300733
734static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
735{
736 int retval = 0;
737 u32 pyld_sz;
738 u8 header[128] = { 0 };
739 u8 *param = NULL;
Amir Levya5361ab2018-05-01 13:25:37 +0300740 bool is_vlan_mode;
Amir Levy9659e592016-10-27 18:08:27 +0300741 struct ipa_ioc_nat_alloc_mem nat_mem;
Amir Levy479cfdd2017-10-26 12:23:14 +0300742 struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc;
Amir Levy9659e592016-10-27 18:08:27 +0300743 struct ipa_ioc_v4_nat_init nat_init;
Amir Levy479cfdd2017-10-26 12:23:14 +0300744 struct ipa_ioc_ipv6ct_init ipv6ct_init;
Amir Levy9659e592016-10-27 18:08:27 +0300745 struct ipa_ioc_v4_nat_del nat_del;
Amir Levy479cfdd2017-10-26 12:23:14 +0300746 struct ipa_ioc_nat_ipv6ct_table_del table_del;
Amir Levy05fccd02017-06-13 16:25:45 +0300747 struct ipa_ioc_nat_pdn_entry mdfy_pdn;
Amir Levy9659e592016-10-27 18:08:27 +0300748 struct ipa_ioc_rm_dependency rm_depend;
Amir Levy479cfdd2017-10-26 12:23:14 +0300749 struct ipa_ioc_nat_dma_cmd *table_dma_cmd;
Amir Levya5361ab2018-05-01 13:25:37 +0300750 struct ipa_ioc_get_vlan_mode vlan_mode;
Amir Levy9659e592016-10-27 18:08:27 +0300751 size_t sz;
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200752 int pre_entry;
Amir Levy9659e592016-10-27 18:08:27 +0300753
754 IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
755
Amir Levy9659e592016-10-27 18:08:27 +0300756 if (_IOC_TYPE(cmd) != IPA_IOC_MAGIC)
757 return -ENOTTY;
Amir Levy9659e592016-10-27 18:08:27 +0300758
Amir Levy05532622016-11-28 12:12:01 +0200759 if (!ipa3_is_ready()) {
760 IPAERR("IPA not ready, waiting for init completion\n");
761 wait_for_completion(&ipa3_ctx->init_completion_obj);
762 }
763
Amir Levy9659e592016-10-27 18:08:27 +0300764 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
765
766 switch (cmd) {
767 case IPA_IOC_ALLOC_NAT_MEM:
Amir Levy479cfdd2017-10-26 12:23:14 +0300768 if (copy_from_user(&nat_mem, (const void __user *)arg,
769 sizeof(struct ipa_ioc_nat_alloc_mem))) {
Amir Levy9659e592016-10-27 18:08:27 +0300770 retval = -EFAULT;
771 break;
772 }
773 /* null terminate the string */
774 nat_mem.dev_name[IPA_RESOURCE_NAME_MAX - 1] = '\0';
775
776 if (ipa3_allocate_nat_device(&nat_mem)) {
777 retval = -EFAULT;
778 break;
779 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300780 if (copy_to_user((void __user *)arg, &nat_mem,
781 sizeof(struct ipa_ioc_nat_alloc_mem))) {
Amir Levy9659e592016-10-27 18:08:27 +0300782 retval = -EFAULT;
783 break;
784 }
785 break;
Amir Levy479cfdd2017-10-26 12:23:14 +0300786 case IPA_IOC_ALLOC_NAT_TABLE:
787 if (copy_from_user(&table_alloc, (const void __user *)arg,
788 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc))) {
789 retval = -EFAULT;
790 break;
791 }
792
793 if (ipa3_allocate_nat_table(&table_alloc)) {
794 retval = -EFAULT;
795 break;
796 }
797 if (table_alloc.offset &&
798 copy_to_user((void __user *)arg, &table_alloc, sizeof(
799 struct ipa_ioc_nat_ipv6ct_table_alloc))) {
800 retval = -EFAULT;
801 break;
802 }
803 break;
804
805 case IPA_IOC_ALLOC_IPV6CT_TABLE:
806 if (copy_from_user(&table_alloc, (const void __user *)arg,
807 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc))) {
808 retval = -EFAULT;
809 break;
810 }
811
812 if (ipa3_allocate_ipv6ct_table(&table_alloc)) {
813 retval = -EFAULT;
814 break;
815 }
816 if (table_alloc.offset &&
817 copy_to_user((void __user *)arg, &table_alloc, sizeof(
818 struct ipa_ioc_nat_ipv6ct_table_alloc))) {
819 retval = -EFAULT;
820 break;
821 }
822 break;
823
Amir Levy9659e592016-10-27 18:08:27 +0300824 case IPA_IOC_V4_INIT_NAT:
Amir Levy479cfdd2017-10-26 12:23:14 +0300825 if (copy_from_user(&nat_init, (const void __user *)arg,
826 sizeof(struct ipa_ioc_v4_nat_init))) {
Amir Levy9659e592016-10-27 18:08:27 +0300827 retval = -EFAULT;
828 break;
829 }
830 if (ipa3_nat_init_cmd(&nat_init)) {
831 retval = -EFAULT;
832 break;
833 }
834 break;
835
Amir Levy479cfdd2017-10-26 12:23:14 +0300836 case IPA_IOC_INIT_IPV6CT_TABLE:
837 if (copy_from_user(&ipv6ct_init, (const void __user *)arg,
838 sizeof(struct ipa_ioc_ipv6ct_init))) {
Amir Levy9659e592016-10-27 18:08:27 +0300839 retval = -EFAULT;
840 break;
841 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300842 if (ipa3_ipv6ct_init_cmd(&ipv6ct_init)) {
843 retval = -EFAULT;
844 break;
845 }
846 break;
847
848 case IPA_IOC_TABLE_DMA_CMD:
849 table_dma_cmd = (struct ipa_ioc_nat_dma_cmd *)header;
850 if (copy_from_user(header, (const void __user *)arg,
851 sizeof(struct ipa_ioc_nat_dma_cmd))) {
852 retval = -EFAULT;
853 break;
854 }
855 pre_entry = table_dma_cmd->entries;
856 pyld_sz = sizeof(struct ipa_ioc_nat_dma_cmd) +
857 pre_entry * sizeof(struct ipa_ioc_nat_dma_one);
Amir Levy9659e592016-10-27 18:08:27 +0300858 param = kzalloc(pyld_sz, GFP_KERNEL);
859 if (!param) {
860 retval = -ENOMEM;
861 break;
862 }
863
Amir Levy479cfdd2017-10-26 12:23:14 +0300864 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300865 retval = -EFAULT;
866 break;
867 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300868 table_dma_cmd = (struct ipa_ioc_nat_dma_cmd *)param;
869
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200870 /* add check in case user-space module compromised */
Amir Levy479cfdd2017-10-26 12:23:14 +0300871 if (unlikely(table_dma_cmd->entries != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530872 IPAERR_RL("current %d pre %d\n",
Amir Levy479cfdd2017-10-26 12:23:14 +0300873 table_dma_cmd->entries, pre_entry);
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200874 retval = -EFAULT;
875 break;
876 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300877 if (ipa3_table_dma_cmd(table_dma_cmd)) {
Amir Levy9659e592016-10-27 18:08:27 +0300878 retval = -EFAULT;
879 break;
880 }
881 break;
882
883 case IPA_IOC_V4_DEL_NAT:
Amir Levy479cfdd2017-10-26 12:23:14 +0300884 if (copy_from_user(&nat_del, (const void __user *)arg,
885 sizeof(struct ipa_ioc_v4_nat_del))) {
Amir Levy9659e592016-10-27 18:08:27 +0300886 retval = -EFAULT;
887 break;
888 }
889 if (ipa3_nat_del_cmd(&nat_del)) {
890 retval = -EFAULT;
891 break;
892 }
893 break;
894
Amir Levy479cfdd2017-10-26 12:23:14 +0300895 case IPA_IOC_DEL_NAT_TABLE:
896 if (copy_from_user(&table_del, (const void __user *)arg,
897 sizeof(struct ipa_ioc_nat_ipv6ct_table_del))) {
898 retval = -EFAULT;
899 break;
900 }
901 if (ipa3_del_nat_table(&table_del)) {
902 retval = -EFAULT;
903 break;
904 }
905 break;
906
907 case IPA_IOC_DEL_IPV6CT_TABLE:
908 if (copy_from_user(&table_del, (const void __user *)arg,
909 sizeof(struct ipa_ioc_nat_ipv6ct_table_del))) {
910 retval = -EFAULT;
911 break;
912 }
913 if (ipa3_del_ipv6ct_table(&table_del)) {
914 retval = -EFAULT;
915 break;
916 }
917 break;
918
Amir Levy05fccd02017-06-13 16:25:45 +0300919 case IPA_IOC_NAT_MODIFY_PDN:
Amir Levy479cfdd2017-10-26 12:23:14 +0300920 if (copy_from_user(&mdfy_pdn, (const void __user *)arg,
Amir Levy05fccd02017-06-13 16:25:45 +0300921 sizeof(struct ipa_ioc_nat_pdn_entry))) {
922 retval = -EFAULT;
923 break;
924 }
Amir Levydc65f4c2017-07-06 09:49:50 +0300925 if (ipa3_nat_mdfy_pdn(&mdfy_pdn)) {
Amir Levy05fccd02017-06-13 16:25:45 +0300926 retval = -EFAULT;
927 break;
928 }
929 break;
930
Amir Levy9659e592016-10-27 18:08:27 +0300931 case IPA_IOC_ADD_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +0300932 if (copy_from_user(header, (const void __user *)arg,
933 sizeof(struct ipa_ioc_add_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +0300934 retval = -EFAULT;
935 break;
936 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200937 pre_entry =
938 ((struct ipa_ioc_add_hdr *)header)->num_hdrs;
Amir Levy9659e592016-10-27 18:08:27 +0300939 pyld_sz =
940 sizeof(struct ipa_ioc_add_hdr) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200941 pre_entry * sizeof(struct ipa_hdr_add);
Amir Levy9659e592016-10-27 18:08:27 +0300942 param = kzalloc(pyld_sz, GFP_KERNEL);
943 if (!param) {
944 retval = -ENOMEM;
945 break;
946 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300947 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300948 retval = -EFAULT;
949 break;
950 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200951 /* add check in case user-space module compromised */
952 if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs
953 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530954 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200955 ((struct ipa_ioc_add_hdr *)param)->num_hdrs,
956 pre_entry);
957 retval = -EFAULT;
958 break;
959 }
Skylar Chang68c37d82018-04-07 16:42:36 -0700960 if (ipa3_add_hdr_usr((struct ipa_ioc_add_hdr *)param,
961 true)) {
Amir Levy9659e592016-10-27 18:08:27 +0300962 retval = -EFAULT;
963 break;
964 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300965 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300966 retval = -EFAULT;
967 break;
968 }
969 break;
970
971 case IPA_IOC_DEL_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +0300972 if (copy_from_user(header, (const void __user *)arg,
973 sizeof(struct ipa_ioc_del_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +0300974 retval = -EFAULT;
975 break;
976 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200977 pre_entry =
978 ((struct ipa_ioc_del_hdr *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +0300979 pyld_sz =
980 sizeof(struct ipa_ioc_del_hdr) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200981 pre_entry * sizeof(struct ipa_hdr_del);
Amir Levy9659e592016-10-27 18:08:27 +0300982 param = kzalloc(pyld_sz, GFP_KERNEL);
983 if (!param) {
984 retval = -ENOMEM;
985 break;
986 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300987 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300988 retval = -EFAULT;
989 break;
990 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200991 /* add check in case user-space module compromised */
992 if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls
993 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530994 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200995 ((struct ipa_ioc_del_hdr *)param)->num_hdls,
996 pre_entry);
997 retval = -EFAULT;
998 break;
999 }
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02001000 if (ipa3_del_hdr_by_user((struct ipa_ioc_del_hdr *)param,
1001 true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001002 retval = -EFAULT;
1003 break;
1004 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001005 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001006 retval = -EFAULT;
1007 break;
1008 }
1009 break;
1010
1011 case IPA_IOC_ADD_RT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001012 if (copy_from_user(header, (const void __user *)arg,
1013 sizeof(struct ipa_ioc_add_rt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001014 retval = -EFAULT;
1015 break;
1016 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001017 pre_entry =
1018 ((struct ipa_ioc_add_rt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001019 pyld_sz =
1020 sizeof(struct ipa_ioc_add_rt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001021 pre_entry * sizeof(struct ipa_rt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001022 param = kzalloc(pyld_sz, GFP_KERNEL);
1023 if (!param) {
1024 retval = -ENOMEM;
1025 break;
1026 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001027 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001028 retval = -EFAULT;
1029 break;
1030 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001031 /* add check in case user-space module compromised */
1032 if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules
1033 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301034 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001035 ((struct ipa_ioc_add_rt_rule *)param)->
1036 num_rules,
1037 pre_entry);
1038 retval = -EFAULT;
1039 break;
1040 }
Skylar Chang68c37d82018-04-07 16:42:36 -07001041 if (ipa3_add_rt_rule_usr((struct ipa_ioc_add_rt_rule *)param,
1042 true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001043 retval = -EFAULT;
1044 break;
1045 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001046 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001047 retval = -EFAULT;
1048 break;
1049 }
1050 break;
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05301051
1052 case IPA_IOC_ADD_RT_RULE_EXT:
1053 if (copy_from_user(header,
1054 (const void __user *)arg,
1055 sizeof(struct ipa_ioc_add_rt_rule_ext))) {
1056 retval = -EFAULT;
1057 break;
1058 }
1059 pre_entry =
1060 ((struct ipa_ioc_add_rt_rule_ext *)header)->num_rules;
1061 pyld_sz =
1062 sizeof(struct ipa_ioc_add_rt_rule_ext) +
1063 pre_entry * sizeof(struct ipa_rt_rule_add_ext);
1064 param = kzalloc(pyld_sz, GFP_KERNEL);
1065 if (!param) {
1066 retval = -ENOMEM;
1067 break;
1068 }
1069 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
1070 retval = -EFAULT;
1071 break;
1072 }
1073 /* add check in case user-space module compromised */
1074 if (unlikely(
1075 ((struct ipa_ioc_add_rt_rule_ext *)param)->num_rules
1076 != pre_entry)) {
1077 IPAERR(" prevent memory corruption(%d not match %d)\n",
1078 ((struct ipa_ioc_add_rt_rule_ext *)param)->
1079 num_rules,
1080 pre_entry);
1081 retval = -EINVAL;
1082 break;
1083 }
1084 if (ipa3_add_rt_rule_ext(
1085 (struct ipa_ioc_add_rt_rule_ext *)param)) {
1086 retval = -EFAULT;
1087 break;
1088 }
1089 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
1090 retval = -EFAULT;
1091 break;
1092 }
1093 break;
Amir Levy9659e592016-10-27 18:08:27 +03001094 case IPA_IOC_ADD_RT_RULE_AFTER:
Amir Levy479cfdd2017-10-26 12:23:14 +03001095 if (copy_from_user(header, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001096 sizeof(struct ipa_ioc_add_rt_rule_after))) {
1097
1098 retval = -EFAULT;
1099 break;
1100 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001101 pre_entry =
1102 ((struct ipa_ioc_add_rt_rule_after *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001103 pyld_sz =
1104 sizeof(struct ipa_ioc_add_rt_rule_after) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001105 pre_entry * sizeof(struct ipa_rt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001106 param = kzalloc(pyld_sz, GFP_KERNEL);
1107 if (!param) {
1108 retval = -ENOMEM;
1109 break;
1110 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001111 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001112 retval = -EFAULT;
1113 break;
1114 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001115 /* add check in case user-space module compromised */
1116 if (unlikely(((struct ipa_ioc_add_rt_rule_after *)param)->
1117 num_rules != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301118 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001119 ((struct ipa_ioc_add_rt_rule_after *)param)->
1120 num_rules,
1121 pre_entry);
1122 retval = -EFAULT;
1123 break;
1124 }
Amir Levy9659e592016-10-27 18:08:27 +03001125 if (ipa3_add_rt_rule_after(
1126 (struct ipa_ioc_add_rt_rule_after *)param)) {
1127
1128 retval = -EFAULT;
1129 break;
1130 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001131 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001132 retval = -EFAULT;
1133 break;
1134 }
1135 break;
1136
1137 case IPA_IOC_MDFY_RT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001138 if (copy_from_user(header, (const void __user *)arg,
1139 sizeof(struct ipa_ioc_mdfy_rt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001140 retval = -EFAULT;
1141 break;
1142 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001143 pre_entry =
1144 ((struct ipa_ioc_mdfy_rt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001145 pyld_sz =
1146 sizeof(struct ipa_ioc_mdfy_rt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001147 pre_entry * sizeof(struct ipa_rt_rule_mdfy);
Amir Levy9659e592016-10-27 18:08:27 +03001148 param = kzalloc(pyld_sz, GFP_KERNEL);
1149 if (!param) {
1150 retval = -ENOMEM;
1151 break;
1152 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001153 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001154 retval = -EFAULT;
1155 break;
1156 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001157 /* add check in case user-space module compromised */
1158 if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules
1159 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301160 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001161 ((struct ipa_ioc_mdfy_rt_rule *)param)->
1162 num_rules,
1163 pre_entry);
1164 retval = -EFAULT;
1165 break;
1166 }
Amir Levy9659e592016-10-27 18:08:27 +03001167 if (ipa3_mdfy_rt_rule((struct ipa_ioc_mdfy_rt_rule *)param)) {
1168 retval = -EFAULT;
1169 break;
1170 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001171 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001172 retval = -EFAULT;
1173 break;
1174 }
1175 break;
1176
1177 case IPA_IOC_DEL_RT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001178 if (copy_from_user(header, (const void __user *)arg,
1179 sizeof(struct ipa_ioc_del_rt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001180 retval = -EFAULT;
1181 break;
1182 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001183 pre_entry =
1184 ((struct ipa_ioc_del_rt_rule *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001185 pyld_sz =
1186 sizeof(struct ipa_ioc_del_rt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001187 pre_entry * sizeof(struct ipa_rt_rule_del);
Amir Levy9659e592016-10-27 18:08:27 +03001188 param = kzalloc(pyld_sz, GFP_KERNEL);
1189 if (!param) {
1190 retval = -ENOMEM;
1191 break;
1192 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001193 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001194 retval = -EFAULT;
1195 break;
1196 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001197 /* add check in case user-space module compromised */
1198 if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls
1199 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301200 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001201 ((struct ipa_ioc_del_rt_rule *)param)->num_hdls,
1202 pre_entry);
1203 retval = -EFAULT;
1204 break;
1205 }
Amir Levy9659e592016-10-27 18:08:27 +03001206 if (ipa3_del_rt_rule((struct ipa_ioc_del_rt_rule *)param)) {
1207 retval = -EFAULT;
1208 break;
1209 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001210 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001211 retval = -EFAULT;
1212 break;
1213 }
1214 break;
1215
1216 case IPA_IOC_ADD_FLT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001217 if (copy_from_user(header, (const void __user *)arg,
1218 sizeof(struct ipa_ioc_add_flt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001219 retval = -EFAULT;
1220 break;
1221 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001222 pre_entry =
1223 ((struct ipa_ioc_add_flt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001224 pyld_sz =
1225 sizeof(struct ipa_ioc_add_flt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001226 pre_entry * sizeof(struct ipa_flt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001227 param = kzalloc(pyld_sz, GFP_KERNEL);
1228 if (!param) {
1229 retval = -ENOMEM;
1230 break;
1231 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001232 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001233 retval = -EFAULT;
1234 break;
1235 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001236 /* add check in case user-space module compromised */
1237 if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules
1238 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301239 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001240 ((struct ipa_ioc_add_flt_rule *)param)->
1241 num_rules,
1242 pre_entry);
1243 retval = -EFAULT;
1244 break;
1245 }
Skylar Chang68c37d82018-04-07 16:42:36 -07001246 if (ipa3_add_flt_rule_usr((struct ipa_ioc_add_flt_rule *)param,
1247 true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001248 retval = -EFAULT;
1249 break;
1250 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001251 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001252 retval = -EFAULT;
1253 break;
1254 }
1255 break;
1256
1257 case IPA_IOC_ADD_FLT_RULE_AFTER:
Amir Levy479cfdd2017-10-26 12:23:14 +03001258 if (copy_from_user(header, (const void __user *)arg,
1259 sizeof(struct ipa_ioc_add_flt_rule_after))) {
Amir Levy9659e592016-10-27 18:08:27 +03001260
1261 retval = -EFAULT;
1262 break;
1263 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001264 pre_entry =
1265 ((struct ipa_ioc_add_flt_rule_after *)header)->
1266 num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001267 pyld_sz =
1268 sizeof(struct ipa_ioc_add_flt_rule_after) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001269 pre_entry * sizeof(struct ipa_flt_rule_add);
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_add_flt_rule_after *)param)->
1281 num_rules != 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_add_flt_rule_after *)param)->
1284 num_rules,
1285 pre_entry);
1286 retval = -EFAULT;
1287 break;
1288 }
Amir Levy9659e592016-10-27 18:08:27 +03001289 if (ipa3_add_flt_rule_after(
1290 (struct ipa_ioc_add_flt_rule_after *)param)) {
1291 retval = -EFAULT;
1292 break;
1293 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001294 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001295 retval = -EFAULT;
1296 break;
1297 }
1298 break;
1299
1300 case IPA_IOC_DEL_FLT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001301 if (copy_from_user(header, (const void __user *)arg,
1302 sizeof(struct ipa_ioc_del_flt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001303 retval = -EFAULT;
1304 break;
1305 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001306 pre_entry =
1307 ((struct ipa_ioc_del_flt_rule *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001308 pyld_sz =
1309 sizeof(struct ipa_ioc_del_flt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001310 pre_entry * sizeof(struct ipa_flt_rule_del);
Amir Levy9659e592016-10-27 18:08:27 +03001311 param = kzalloc(pyld_sz, GFP_KERNEL);
1312 if (!param) {
1313 retval = -ENOMEM;
1314 break;
1315 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001316 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001317 retval = -EFAULT;
1318 break;
1319 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001320 /* add check in case user-space module compromised */
1321 if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls
1322 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301323 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001324 ((struct ipa_ioc_del_flt_rule *)param)->
1325 num_hdls,
1326 pre_entry);
1327 retval = -EFAULT;
1328 break;
1329 }
Amir Levy9659e592016-10-27 18:08:27 +03001330 if (ipa3_del_flt_rule((struct ipa_ioc_del_flt_rule *)param)) {
1331 retval = -EFAULT;
1332 break;
1333 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001334 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001335 retval = -EFAULT;
1336 break;
1337 }
1338 break;
1339
1340 case IPA_IOC_MDFY_FLT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001341 if (copy_from_user(header, (const void __user *)arg,
1342 sizeof(struct ipa_ioc_mdfy_flt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001343 retval = -EFAULT;
1344 break;
1345 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001346 pre_entry =
1347 ((struct ipa_ioc_mdfy_flt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001348 pyld_sz =
1349 sizeof(struct ipa_ioc_mdfy_flt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001350 pre_entry * sizeof(struct ipa_flt_rule_mdfy);
Amir Levy9659e592016-10-27 18:08:27 +03001351 param = kzalloc(pyld_sz, GFP_KERNEL);
1352 if (!param) {
1353 retval = -ENOMEM;
1354 break;
1355 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001356 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001357 retval = -EFAULT;
1358 break;
1359 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001360 /* add check in case user-space module compromised */
1361 if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules
1362 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301363 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001364 ((struct ipa_ioc_mdfy_flt_rule *)param)->
1365 num_rules,
1366 pre_entry);
1367 retval = -EFAULT;
1368 break;
1369 }
Amir Levy9659e592016-10-27 18:08:27 +03001370 if (ipa3_mdfy_flt_rule((struct ipa_ioc_mdfy_flt_rule *)param)) {
1371 retval = -EFAULT;
1372 break;
1373 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001374 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001375 retval = -EFAULT;
1376 break;
1377 }
1378 break;
1379
1380 case IPA_IOC_COMMIT_HDR:
1381 retval = ipa3_commit_hdr();
1382 break;
1383 case IPA_IOC_RESET_HDR:
Skylar Chang68c37d82018-04-07 16:42:36 -07001384 retval = ipa3_reset_hdr(false);
Amir Levy9659e592016-10-27 18:08:27 +03001385 break;
1386 case IPA_IOC_COMMIT_RT:
1387 retval = ipa3_commit_rt(arg);
1388 break;
1389 case IPA_IOC_RESET_RT:
Skylar Chang68c37d82018-04-07 16:42:36 -07001390 retval = ipa3_reset_rt(arg, false);
Amir Levy9659e592016-10-27 18:08:27 +03001391 break;
1392 case IPA_IOC_COMMIT_FLT:
1393 retval = ipa3_commit_flt(arg);
1394 break;
1395 case IPA_IOC_RESET_FLT:
Skylar Chang68c37d82018-04-07 16:42:36 -07001396 retval = ipa3_reset_flt(arg, false);
Amir Levy9659e592016-10-27 18:08:27 +03001397 break;
1398 case IPA_IOC_GET_RT_TBL:
Amir Levy479cfdd2017-10-26 12:23:14 +03001399 if (copy_from_user(header, (const void __user *)arg,
1400 sizeof(struct ipa_ioc_get_rt_tbl))) {
Amir Levy9659e592016-10-27 18:08:27 +03001401 retval = -EFAULT;
1402 break;
1403 }
1404 if (ipa3_get_rt_tbl((struct ipa_ioc_get_rt_tbl *)header)) {
1405 retval = -EFAULT;
1406 break;
1407 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001408 if (copy_to_user((void __user *)arg, header,
Amir Levy9659e592016-10-27 18:08:27 +03001409 sizeof(struct ipa_ioc_get_rt_tbl))) {
1410 retval = -EFAULT;
1411 break;
1412 }
1413 break;
1414 case IPA_IOC_PUT_RT_TBL:
1415 retval = ipa3_put_rt_tbl(arg);
1416 break;
1417 case IPA_IOC_GET_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +03001418 if (copy_from_user(header, (const void __user *)arg,
1419 sizeof(struct ipa_ioc_get_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001420 retval = -EFAULT;
1421 break;
1422 }
1423 if (ipa3_get_hdr((struct ipa_ioc_get_hdr *)header)) {
1424 retval = -EFAULT;
1425 break;
1426 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001427 if (copy_to_user((void __user *)arg, header,
1428 sizeof(struct ipa_ioc_get_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001429 retval = -EFAULT;
1430 break;
1431 }
1432 break;
1433 case IPA_IOC_PUT_HDR:
1434 retval = ipa3_put_hdr(arg);
1435 break;
1436 case IPA_IOC_SET_FLT:
1437 retval = ipa3_cfg_filter(arg);
1438 break;
1439 case IPA_IOC_COPY_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +03001440 if (copy_from_user(header, (const void __user *)arg,
1441 sizeof(struct ipa_ioc_copy_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001442 retval = -EFAULT;
1443 break;
1444 }
1445 if (ipa3_copy_hdr((struct ipa_ioc_copy_hdr *)header)) {
1446 retval = -EFAULT;
1447 break;
1448 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001449 if (copy_to_user((void __user *)arg, header,
1450 sizeof(struct ipa_ioc_copy_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001451 retval = -EFAULT;
1452 break;
1453 }
1454 break;
1455 case IPA_IOC_QUERY_INTF:
Amir Levy479cfdd2017-10-26 12:23:14 +03001456 if (copy_from_user(header, (const void __user *)arg,
1457 sizeof(struct ipa_ioc_query_intf))) {
Amir Levy9659e592016-10-27 18:08:27 +03001458 retval = -EFAULT;
1459 break;
1460 }
1461 if (ipa3_query_intf((struct ipa_ioc_query_intf *)header)) {
1462 retval = -1;
1463 break;
1464 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001465 if (copy_to_user((void __user *)arg, header,
1466 sizeof(struct ipa_ioc_query_intf))) {
Amir Levy9659e592016-10-27 18:08:27 +03001467 retval = -EFAULT;
1468 break;
1469 }
1470 break;
1471 case IPA_IOC_QUERY_INTF_TX_PROPS:
1472 sz = sizeof(struct ipa_ioc_query_intf_tx_props);
Amir Levy479cfdd2017-10-26 12:23:14 +03001473 if (copy_from_user(header, (const void __user *)arg, sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001474 retval = -EFAULT;
1475 break;
1476 }
1477
1478 if (((struct ipa_ioc_query_intf_tx_props *)header)->num_tx_props
Amir Levy479cfdd2017-10-26 12:23:14 +03001479 > IPA_NUM_PROPS_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001480 retval = -EFAULT;
1481 break;
1482 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001483 pre_entry =
1484 ((struct ipa_ioc_query_intf_tx_props *)
1485 header)->num_tx_props;
1486 pyld_sz = sz + pre_entry *
Amir Levy9659e592016-10-27 18:08:27 +03001487 sizeof(struct ipa_ioc_tx_intf_prop);
1488 param = kzalloc(pyld_sz, GFP_KERNEL);
1489 if (!param) {
1490 retval = -ENOMEM;
1491 break;
1492 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001493 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001494 retval = -EFAULT;
1495 break;
1496 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001497 /* add check in case user-space module compromised */
1498 if (unlikely(((struct ipa_ioc_query_intf_tx_props *)
1499 param)->num_tx_props
1500 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301501 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001502 ((struct ipa_ioc_query_intf_tx_props *)
1503 param)->num_tx_props, pre_entry);
1504 retval = -EFAULT;
1505 break;
1506 }
Amir Levy9659e592016-10-27 18:08:27 +03001507 if (ipa3_query_intf_tx_props(
Amir Levy479cfdd2017-10-26 12:23:14 +03001508 (struct ipa_ioc_query_intf_tx_props *)param)) {
Amir Levy9659e592016-10-27 18:08:27 +03001509 retval = -1;
1510 break;
1511 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001512 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001513 retval = -EFAULT;
1514 break;
1515 }
1516 break;
1517 case IPA_IOC_QUERY_INTF_RX_PROPS:
1518 sz = sizeof(struct ipa_ioc_query_intf_rx_props);
Amir Levy479cfdd2017-10-26 12:23:14 +03001519 if (copy_from_user(header, (const void __user *)arg, sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001520 retval = -EFAULT;
1521 break;
1522 }
1523
1524 if (((struct ipa_ioc_query_intf_rx_props *)header)->num_rx_props
Amir Levy479cfdd2017-10-26 12:23:14 +03001525 > IPA_NUM_PROPS_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001526 retval = -EFAULT;
1527 break;
1528 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001529 pre_entry =
1530 ((struct ipa_ioc_query_intf_rx_props *)
1531 header)->num_rx_props;
1532 pyld_sz = sz + pre_entry *
Amir Levy9659e592016-10-27 18:08:27 +03001533 sizeof(struct ipa_ioc_rx_intf_prop);
1534 param = kzalloc(pyld_sz, GFP_KERNEL);
1535 if (!param) {
1536 retval = -ENOMEM;
1537 break;
1538 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001539 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001540 retval = -EFAULT;
1541 break;
1542 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001543 /* add check in case user-space module compromised */
1544 if (unlikely(((struct ipa_ioc_query_intf_rx_props *)
1545 param)->num_rx_props != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301546 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001547 ((struct ipa_ioc_query_intf_rx_props *)
1548 param)->num_rx_props, pre_entry);
1549 retval = -EFAULT;
1550 break;
1551 }
Amir Levy9659e592016-10-27 18:08:27 +03001552 if (ipa3_query_intf_rx_props(
Amir Levy479cfdd2017-10-26 12:23:14 +03001553 (struct ipa_ioc_query_intf_rx_props *)param)) {
Amir Levy9659e592016-10-27 18:08:27 +03001554 retval = -1;
1555 break;
1556 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001557 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001558 retval = -EFAULT;
1559 break;
1560 }
1561 break;
1562 case IPA_IOC_QUERY_INTF_EXT_PROPS:
1563 sz = sizeof(struct ipa_ioc_query_intf_ext_props);
Amir Levy479cfdd2017-10-26 12:23:14 +03001564 if (copy_from_user(header, (const void __user *)arg, sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001565 retval = -EFAULT;
1566 break;
1567 }
1568
1569 if (((struct ipa_ioc_query_intf_ext_props *)
Amir Levy479cfdd2017-10-26 12:23:14 +03001570 header)->num_ext_props > IPA_NUM_PROPS_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001571 retval = -EFAULT;
1572 break;
1573 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001574 pre_entry =
1575 ((struct ipa_ioc_query_intf_ext_props *)
1576 header)->num_ext_props;
1577 pyld_sz = sz + pre_entry *
Amir Levy9659e592016-10-27 18:08:27 +03001578 sizeof(struct ipa_ioc_ext_intf_prop);
1579 param = kzalloc(pyld_sz, GFP_KERNEL);
1580 if (!param) {
1581 retval = -ENOMEM;
1582 break;
1583 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001584 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001585 retval = -EFAULT;
1586 break;
1587 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001588 /* add check in case user-space module compromised */
1589 if (unlikely(((struct ipa_ioc_query_intf_ext_props *)
1590 param)->num_ext_props != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301591 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001592 ((struct ipa_ioc_query_intf_ext_props *)
1593 param)->num_ext_props, pre_entry);
1594 retval = -EFAULT;
1595 break;
1596 }
Amir Levy9659e592016-10-27 18:08:27 +03001597 if (ipa3_query_intf_ext_props(
Amir Levy479cfdd2017-10-26 12:23:14 +03001598 (struct ipa_ioc_query_intf_ext_props *)param)) {
Amir Levy9659e592016-10-27 18:08:27 +03001599 retval = -1;
1600 break;
1601 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001602 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001603 retval = -EFAULT;
1604 break;
1605 }
1606 break;
1607 case IPA_IOC_PULL_MSG:
Amir Levy479cfdd2017-10-26 12:23:14 +03001608 if (copy_from_user(header, (const void __user *)arg,
1609 sizeof(struct ipa_msg_meta))) {
Amir Levy9659e592016-10-27 18:08:27 +03001610 retval = -EFAULT;
1611 break;
1612 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001613 pre_entry =
Amir Levy9659e592016-10-27 18:08:27 +03001614 ((struct ipa_msg_meta *)header)->msg_len;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001615 pyld_sz = sizeof(struct ipa_msg_meta) +
1616 pre_entry;
Amir Levy9659e592016-10-27 18:08:27 +03001617 param = kzalloc(pyld_sz, GFP_KERNEL);
1618 if (!param) {
1619 retval = -ENOMEM;
1620 break;
1621 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001622 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001623 retval = -EFAULT;
1624 break;
1625 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001626 /* add check in case user-space module compromised */
1627 if (unlikely(((struct ipa_msg_meta *)param)->msg_len
1628 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301629 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001630 ((struct ipa_msg_meta *)param)->msg_len,
1631 pre_entry);
1632 retval = -EFAULT;
1633 break;
1634 }
Amir Levy9659e592016-10-27 18:08:27 +03001635 if (ipa3_pull_msg((struct ipa_msg_meta *)param,
Amir Levy479cfdd2017-10-26 12:23:14 +03001636 (char *)param + sizeof(struct ipa_msg_meta),
1637 ((struct ipa_msg_meta *)param)->msg_len) !=
1638 ((struct ipa_msg_meta *)param)->msg_len) {
Amir Levy9659e592016-10-27 18:08:27 +03001639 retval = -1;
1640 break;
1641 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001642 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001643 retval = -EFAULT;
1644 break;
1645 }
1646 break;
1647 case IPA_IOC_RM_ADD_DEPENDENCY:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001648 /* deprecate if IPA PM is used */
1649 if (ipa3_ctx->use_ipa_pm)
1650 return 0;
1651
Amir Levy479cfdd2017-10-26 12:23:14 +03001652 if (copy_from_user(&rm_depend, (const void __user *)arg,
1653 sizeof(struct ipa_ioc_rm_dependency))) {
Amir Levy9659e592016-10-27 18:08:27 +03001654 retval = -EFAULT;
1655 break;
1656 }
1657 retval = ipa_rm_add_dependency_from_ioctl(
1658 rm_depend.resource_name, rm_depend.depends_on_name);
1659 break;
1660 case IPA_IOC_RM_DEL_DEPENDENCY:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001661 /* deprecate if IPA PM is used */
1662 if (ipa3_ctx->use_ipa_pm)
1663 return 0;
1664
Amir Levy479cfdd2017-10-26 12:23:14 +03001665 if (copy_from_user(&rm_depend, (const void __user *)arg,
1666 sizeof(struct ipa_ioc_rm_dependency))) {
Amir Levy9659e592016-10-27 18:08:27 +03001667 retval = -EFAULT;
1668 break;
1669 }
1670 retval = ipa_rm_delete_dependency_from_ioctl(
1671 rm_depend.resource_name, rm_depend.depends_on_name);
1672 break;
1673 case IPA_IOC_GENERATE_FLT_EQ:
1674 {
1675 struct ipa_ioc_generate_flt_eq flt_eq;
1676
Amir Levy479cfdd2017-10-26 12:23:14 +03001677 if (copy_from_user(&flt_eq, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001678 sizeof(struct ipa_ioc_generate_flt_eq))) {
1679 retval = -EFAULT;
1680 break;
1681 }
1682 if (ipahal_flt_generate_equation(flt_eq.ip,
1683 &flt_eq.attrib, &flt_eq.eq_attrib)) {
1684 retval = -EFAULT;
1685 break;
1686 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001687 if (copy_to_user((void __user *)arg, &flt_eq,
Amir Levy9659e592016-10-27 18:08:27 +03001688 sizeof(struct ipa_ioc_generate_flt_eq))) {
1689 retval = -EFAULT;
1690 break;
1691 }
1692 break;
1693 }
1694 case IPA_IOC_QUERY_EP_MAPPING:
1695 {
1696 retval = ipa3_get_ep_mapping(arg);
1697 break;
1698 }
1699 case IPA_IOC_QUERY_RT_TBL_INDEX:
Amir Levy479cfdd2017-10-26 12:23:14 +03001700 if (copy_from_user(header, (const void __user *)arg,
1701 sizeof(struct ipa_ioc_get_rt_tbl_indx))) {
Amir Levy9659e592016-10-27 18:08:27 +03001702 retval = -EFAULT;
1703 break;
1704 }
1705 if (ipa3_query_rt_index(
Amir Levy479cfdd2017-10-26 12:23:14 +03001706 (struct ipa_ioc_get_rt_tbl_indx *)header)) {
Amir Levy9659e592016-10-27 18:08:27 +03001707 retval = -EFAULT;
1708 break;
1709 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001710 if (copy_to_user((void __user *)arg, header,
1711 sizeof(struct ipa_ioc_get_rt_tbl_indx))) {
Amir Levy9659e592016-10-27 18:08:27 +03001712 retval = -EFAULT;
1713 break;
1714 }
1715 break;
1716 case IPA_IOC_WRITE_QMAPID:
Amir Levy479cfdd2017-10-26 12:23:14 +03001717 if (copy_from_user(header, (const void __user *)arg,
1718 sizeof(struct ipa_ioc_write_qmapid))) {
Amir Levy9659e592016-10-27 18:08:27 +03001719 retval = -EFAULT;
1720 break;
1721 }
1722 if (ipa3_write_qmap_id((struct ipa_ioc_write_qmapid *)header)) {
1723 retval = -EFAULT;
1724 break;
1725 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001726 if (copy_to_user((void __user *)arg, header,
1727 sizeof(struct ipa_ioc_write_qmapid))) {
Amir Levy9659e592016-10-27 18:08:27 +03001728 retval = -EFAULT;
1729 break;
1730 }
1731 break;
1732 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD:
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05301733 retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD, true);
Amir Levy9659e592016-10-27 18:08:27 +03001734 if (retval) {
1735 IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
1736 break;
1737 }
1738 break;
1739 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL:
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05301740 retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL, true);
Amir Levy9659e592016-10-27 18:08:27 +03001741 if (retval) {
1742 IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
1743 break;
1744 }
1745 break;
1746 case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED:
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05301747 retval = ipa3_send_wan_msg(arg, WAN_EMBMS_CONNECT, false);
Amir Levy9659e592016-10-27 18:08:27 +03001748 if (retval) {
1749 IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
1750 break;
1751 }
1752 break;
1753 case IPA_IOC_ADD_HDR_PROC_CTX:
Amir Levy479cfdd2017-10-26 12:23:14 +03001754 if (copy_from_user(header, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001755 sizeof(struct ipa_ioc_add_hdr_proc_ctx))) {
1756 retval = -EFAULT;
1757 break;
1758 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001759 pre_entry =
1760 ((struct ipa_ioc_add_hdr_proc_ctx *)
1761 header)->num_proc_ctxs;
Amir Levy9659e592016-10-27 18:08:27 +03001762 pyld_sz =
1763 sizeof(struct ipa_ioc_add_hdr_proc_ctx) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001764 pre_entry * sizeof(struct ipa_hdr_proc_ctx_add);
Amir Levy9659e592016-10-27 18:08:27 +03001765 param = kzalloc(pyld_sz, GFP_KERNEL);
1766 if (!param) {
1767 retval = -ENOMEM;
1768 break;
1769 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001770 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001771 retval = -EFAULT;
1772 break;
1773 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001774 /* add check in case user-space module compromised */
1775 if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *)
1776 param)->num_proc_ctxs != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301777 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001778 ((struct ipa_ioc_add_hdr_proc_ctx *)
1779 param)->num_proc_ctxs, pre_entry);
1780 retval = -EFAULT;
1781 break;
1782 }
Amir Levy9659e592016-10-27 18:08:27 +03001783 if (ipa3_add_hdr_proc_ctx(
Skylar Chang68c37d82018-04-07 16:42:36 -07001784 (struct ipa_ioc_add_hdr_proc_ctx *)param, true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001785 retval = -EFAULT;
1786 break;
1787 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001788 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001789 retval = -EFAULT;
1790 break;
1791 }
1792 break;
1793 case IPA_IOC_DEL_HDR_PROC_CTX:
Amir Levy479cfdd2017-10-26 12:23:14 +03001794 if (copy_from_user(header, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001795 sizeof(struct ipa_ioc_del_hdr_proc_ctx))) {
1796 retval = -EFAULT;
1797 break;
1798 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001799 pre_entry =
1800 ((struct ipa_ioc_del_hdr_proc_ctx *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001801 pyld_sz =
1802 sizeof(struct ipa_ioc_del_hdr_proc_ctx) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001803 pre_entry * sizeof(struct ipa_hdr_proc_ctx_del);
Amir Levy9659e592016-10-27 18:08:27 +03001804 param = kzalloc(pyld_sz, GFP_KERNEL);
1805 if (!param) {
1806 retval = -ENOMEM;
1807 break;
1808 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001809 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001810 retval = -EFAULT;
1811 break;
1812 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001813 /* add check in case user-space module compromised */
1814 if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *)
1815 param)->num_hdls != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301816 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001817 ((struct ipa_ioc_del_hdr_proc_ctx *)param)->
1818 num_hdls,
1819 pre_entry);
1820 retval = -EFAULT;
1821 break;
1822 }
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02001823 if (ipa3_del_hdr_proc_ctx_by_user(
1824 (struct ipa_ioc_del_hdr_proc_ctx *)param, true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001825 retval = -EFAULT;
1826 break;
1827 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001828 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001829 retval = -EFAULT;
1830 break;
1831 }
1832 break;
1833
1834 case IPA_IOC_GET_HW_VERSION:
1835 pyld_sz = sizeof(enum ipa_hw_type);
1836 param = kzalloc(pyld_sz, GFP_KERNEL);
1837 if (!param) {
1838 retval = -ENOMEM;
1839 break;
1840 }
1841 memcpy(param, &ipa3_ctx->ipa_hw_type, pyld_sz);
Amir Levy479cfdd2017-10-26 12:23:14 +03001842 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001843 retval = -EFAULT;
1844 break;
1845 }
1846 break;
1847
Amir Levya5361ab2018-05-01 13:25:37 +03001848 case IPA_IOC_GET_VLAN_MODE:
1849 if (copy_from_user(&vlan_mode, (const void __user *)arg,
1850 sizeof(struct ipa_ioc_get_vlan_mode))) {
1851 retval = -EFAULT;
1852 break;
1853 }
1854 retval = ipa3_is_vlan_mode(
1855 vlan_mode.iface,
1856 &is_vlan_mode);
1857 if (retval)
1858 break;
1859
1860 vlan_mode.is_vlan_mode = is_vlan_mode;
1861
1862 if (copy_to_user((void __user *)arg,
1863 &vlan_mode,
1864 sizeof(struct ipa_ioc_get_vlan_mode))) {
1865 retval = -EFAULT;
1866 break;
1867 }
1868 break;
1869
Shihuan Liuc3174f52017-05-04 15:59:13 -07001870 case IPA_IOC_ADD_VLAN_IFACE:
1871 if (ipa3_send_vlan_l2tp_msg(arg, ADD_VLAN_IFACE)) {
1872 retval = -EFAULT;
1873 break;
1874 }
1875 break;
1876
1877 case IPA_IOC_DEL_VLAN_IFACE:
1878 if (ipa3_send_vlan_l2tp_msg(arg, DEL_VLAN_IFACE)) {
1879 retval = -EFAULT;
1880 break;
1881 }
1882 break;
1883
1884 case IPA_IOC_ADD_L2TP_VLAN_MAPPING:
1885 if (ipa3_send_vlan_l2tp_msg(arg, ADD_L2TP_VLAN_MAPPING)) {
1886 retval = -EFAULT;
1887 break;
1888 }
1889 break;
1890
1891 case IPA_IOC_DEL_L2TP_VLAN_MAPPING:
1892 if (ipa3_send_vlan_l2tp_msg(arg, DEL_L2TP_VLAN_MAPPING)) {
1893 retval = -EFAULT;
1894 break;
1895 }
1896 break;
1897
Skylar Chang68c37d82018-04-07 16:42:36 -07001898 case IPA_IOC_CLEANUP:
1899 /*Route and filter rules will also be clean*/
1900 IPADBG("Got IPA_IOC_CLEANUP\n");
1901 retval = ipa3_reset_hdr(true);
1902 memset(&nat_del, 0, sizeof(nat_del));
1903 nat_del.table_index = 0;
1904 retval = ipa3_nat_del_cmd(&nat_del);
1905 retval = ipa3_clean_modem_rule();
1906 break;
1907
1908 case IPA_IOC_QUERY_WLAN_CLIENT:
1909 IPADBG("Got IPA_IOC_QUERY_WLAN_CLIENT\n");
1910 retval = ipa3_resend_wlan_msg();
1911 break;
1912
Amir Levy479cfdd2017-10-26 12:23:14 +03001913 default:
Amir Levy9659e592016-10-27 18:08:27 +03001914 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
1915 return -ENOTTY;
1916 }
1917 kfree(param);
1918 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
1919
1920 return retval;
1921}
1922
1923/**
Skylar Chang68c37d82018-04-07 16:42:36 -07001924 * ipa3_setup_dflt_rt_tables() - Setup default routing tables
1925 *
1926 * Return codes:
1927 * 0: success
1928 * -ENOMEM: failed to allocate memory
1929 * -EPERM: failed to add the tables
1930 */
Amir Levy9659e592016-10-27 18:08:27 +03001931int ipa3_setup_dflt_rt_tables(void)
1932{
1933 struct ipa_ioc_add_rt_rule *rt_rule;
1934 struct ipa_rt_rule_add *rt_rule_entry;
1935
1936 rt_rule =
Amir Levy479cfdd2017-10-26 12:23:14 +03001937 kzalloc(sizeof(struct ipa_ioc_add_rt_rule) + 1 *
1938 sizeof(struct ipa_rt_rule_add), GFP_KERNEL);
Amir Levy9659e592016-10-27 18:08:27 +03001939 if (!rt_rule) {
1940 IPAERR("fail to alloc mem\n");
1941 return -ENOMEM;
1942 }
1943 /* setup a default v4 route to point to Apps */
1944 rt_rule->num_rules = 1;
1945 rt_rule->commit = 1;
1946 rt_rule->ip = IPA_IP_v4;
1947 strlcpy(rt_rule->rt_tbl_name, IPA_DFLT_RT_TBL_NAME,
Amir Levy479cfdd2017-10-26 12:23:14 +03001948 IPA_RESOURCE_NAME_MAX);
Amir Levy9659e592016-10-27 18:08:27 +03001949
1950 rt_rule_entry = &rt_rule->rules[0];
1951 rt_rule_entry->at_rear = 1;
1952 rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
1953 rt_rule_entry->rule.hdr_hdl = ipa3_ctx->excp_hdr_hdl;
1954 rt_rule_entry->rule.retain_hdr = 1;
1955
1956 if (ipa3_add_rt_rule(rt_rule)) {
1957 IPAERR("fail to add dflt v4 rule\n");
1958 kfree(rt_rule);
1959 return -EPERM;
1960 }
1961 IPADBG("dflt v4 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
1962 ipa3_ctx->dflt_v4_rt_rule_hdl = rt_rule_entry->rt_rule_hdl;
1963
1964 /* setup a default v6 route to point to A5 */
1965 rt_rule->ip = IPA_IP_v6;
1966 if (ipa3_add_rt_rule(rt_rule)) {
1967 IPAERR("fail to add dflt v6 rule\n");
1968 kfree(rt_rule);
1969 return -EPERM;
1970 }
1971 IPADBG("dflt v6 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
1972 ipa3_ctx->dflt_v6_rt_rule_hdl = rt_rule_entry->rt_rule_hdl;
1973
1974 /*
1975 * because these tables are the very first to be added, they will both
1976 * have the same index (0) which is essential for programming the
1977 * "route" end-point config
1978 */
1979
1980 kfree(rt_rule);
1981
1982 return 0;
1983}
1984
1985static int ipa3_setup_exception_path(void)
1986{
1987 struct ipa_ioc_add_hdr *hdr;
1988 struct ipa_hdr_add *hdr_entry;
1989 struct ipahal_reg_route route = { 0 };
1990 int ret;
1991
1992 /* install the basic exception header */
1993 hdr = kzalloc(sizeof(struct ipa_ioc_add_hdr) + 1 *
1994 sizeof(struct ipa_hdr_add), GFP_KERNEL);
1995 if (!hdr) {
1996 IPAERR("fail to alloc exception hdr\n");
1997 return -ENOMEM;
1998 }
1999 hdr->num_hdrs = 1;
2000 hdr->commit = 1;
2001 hdr_entry = &hdr->hdr[0];
2002
2003 strlcpy(hdr_entry->name, IPA_LAN_RX_HDR_NAME, IPA_RESOURCE_NAME_MAX);
2004 hdr_entry->hdr_len = IPA_LAN_RX_HEADER_LENGTH;
2005
2006 if (ipa3_add_hdr(hdr)) {
2007 IPAERR("fail to add exception hdr\n");
2008 ret = -EPERM;
2009 goto bail;
2010 }
2011
2012 if (hdr_entry->status) {
2013 IPAERR("fail to add exception hdr\n");
2014 ret = -EPERM;
2015 goto bail;
2016 }
2017
2018 ipa3_ctx->excp_hdr_hdl = hdr_entry->hdr_hdl;
2019
2020 /* set the route register to pass exception packets to Apps */
2021 route.route_def_pipe = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS);
2022 route.route_frag_def_pipe = ipa3_get_ep_mapping(
2023 IPA_CLIENT_APPS_LAN_CONS);
2024 route.route_def_hdr_table = !ipa3_ctx->hdr_tbl_lcl;
2025 route.route_def_retain_hdr = 1;
2026
2027 if (ipa3_cfg_route(&route)) {
2028 IPAERR("fail to add exception hdr\n");
2029 ret = -EPERM;
2030 goto bail;
2031 }
2032
2033 ret = 0;
2034bail:
2035 kfree(hdr);
2036 return ret;
2037}
2038
2039static int ipa3_init_smem_region(int memory_region_size,
2040 int memory_region_offset)
2041{
2042 struct ipahal_imm_cmd_dma_shared_mem cmd;
2043 struct ipahal_imm_cmd_pyld *cmd_pyld;
2044 struct ipa3_desc desc;
2045 struct ipa_mem_buffer mem;
2046 int rc;
2047
2048 if (memory_region_size == 0)
2049 return 0;
2050
2051 memset(&desc, 0, sizeof(desc));
2052 memset(&cmd, 0, sizeof(cmd));
2053 memset(&mem, 0, sizeof(mem));
2054
2055 mem.size = memory_region_size;
2056 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
2057 &mem.phys_base, GFP_KERNEL);
2058 if (!mem.base) {
2059 IPAERR("failed to alloc DMA buff of size %d\n", mem.size);
2060 return -ENOMEM;
2061 }
2062
2063 memset(mem.base, 0, mem.size);
2064 cmd.is_read = false;
2065 cmd.skip_pipeline_clear = false;
2066 cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2067 cmd.size = mem.size;
2068 cmd.system_addr = mem.phys_base;
2069 cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
2070 memory_region_offset;
2071 cmd_pyld = ipahal_construct_imm_cmd(
2072 IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
2073 if (!cmd_pyld) {
2074 IPAERR("failed to construct dma_shared_mem imm cmd\n");
2075 return -ENOMEM;
2076 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002077 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002078
2079 rc = ipa3_send_cmd(1, &desc);
2080 if (rc) {
2081 IPAERR("failed to send immediate command (error %d)\n", rc);
2082 rc = -EFAULT;
2083 }
2084
2085 ipahal_destroy_imm_cmd(cmd_pyld);
2086 dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base,
2087 mem.phys_base);
2088
2089 return rc;
2090}
2091
2092/**
Skylar Chang68c37d82018-04-07 16:42:36 -07002093 * ipa3_init_q6_smem() - Initialize Q6 general memory and
2094 * header memory regions in IPA.
2095 *
2096 * Return codes:
2097 * 0: success
2098 * -ENOMEM: failed to allocate dma memory
2099 * -EFAULT: failed to send IPA command to initialize the memory
2100 */
Amir Levy9659e592016-10-27 18:08:27 +03002101int ipa3_init_q6_smem(void)
2102{
2103 int rc;
2104
2105 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
2106
2107 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_size),
2108 IPA_MEM_PART(modem_ofst));
2109 if (rc) {
2110 IPAERR("failed to initialize Modem RAM memory\n");
2111 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2112 return rc;
2113 }
2114
2115 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_hdr_size),
2116 IPA_MEM_PART(modem_hdr_ofst));
2117 if (rc) {
2118 IPAERR("failed to initialize Modem HDRs RAM memory\n");
2119 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2120 return rc;
2121 }
2122
2123 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_hdr_proc_ctx_size),
2124 IPA_MEM_PART(modem_hdr_proc_ctx_ofst));
2125 if (rc) {
2126 IPAERR("failed to initialize Modem proc ctx RAM memory\n");
2127 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2128 return rc;
2129 }
2130
2131 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_comp_decomp_size),
2132 IPA_MEM_PART(modem_comp_decomp_ofst));
2133 if (rc) {
2134 IPAERR("failed to initialize Modem Comp/Decomp RAM memory\n");
2135 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2136 return rc;
2137 }
2138 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2139
2140 return rc;
2141}
2142
2143static void ipa3_destroy_imm(void *user1, int user2)
2144{
2145 ipahal_destroy_imm_cmd(user1);
2146}
2147
2148static void ipa3_q6_pipe_delay(bool delay)
2149{
2150 int client_idx;
2151 int ep_idx;
2152 struct ipa_ep_cfg_ctrl ep_ctrl;
2153
2154 memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
2155 ep_ctrl.ipa_ep_delay = delay;
2156
2157 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2158 if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
2159 ep_idx = ipa3_get_ep_mapping(client_idx);
2160 if (ep_idx == -1)
2161 continue;
2162
2163 ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n,
2164 ep_idx, &ep_ctrl);
2165 }
2166 }
2167}
2168
2169static void ipa3_q6_avoid_holb(void)
2170{
2171 int ep_idx;
2172 int client_idx;
2173 struct ipa_ep_cfg_ctrl ep_suspend;
2174 struct ipa_ep_cfg_holb ep_holb;
2175
2176 memset(&ep_suspend, 0, sizeof(ep_suspend));
2177 memset(&ep_holb, 0, sizeof(ep_holb));
2178
2179 ep_suspend.ipa_ep_suspend = true;
2180 ep_holb.tmr_val = 0;
2181 ep_holb.en = 1;
2182
2183 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2184 if (IPA_CLIENT_IS_Q6_CONS(client_idx)) {
2185 ep_idx = ipa3_get_ep_mapping(client_idx);
2186 if (ep_idx == -1)
2187 continue;
2188
Skylar Changde679dc2017-11-21 10:11:34 -08002189 /* from IPA 4.0 pipe suspend is not supported */
2190 if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
2191 ipahal_write_reg_n_fields(
2192 IPA_ENDP_INIT_CTRL_n,
2193 ep_idx, &ep_suspend);
2194
Amir Levy9659e592016-10-27 18:08:27 +03002195 /*
2196 * ipa3_cfg_ep_holb is not used here because we are
2197 * setting HOLB on Q6 pipes, and from APPS perspective
2198 * they are not valid, therefore, the above function
2199 * will fail.
2200 */
2201 ipahal_write_reg_n_fields(
2202 IPA_ENDP_INIT_HOL_BLOCK_TIMER_n,
2203 ep_idx, &ep_holb);
2204 ipahal_write_reg_n_fields(
2205 IPA_ENDP_INIT_HOL_BLOCK_EN_n,
2206 ep_idx, &ep_holb);
Amir Levy9659e592016-10-27 18:08:27 +03002207 }
2208 }
2209}
2210
Michael Adisumarta0090e542018-03-14 10:44:53 -07002211static void ipa3_halt_q6_gsi_channels(bool prod)
Skylar Chang94692c92017-03-01 09:07:11 -08002212{
2213 int ep_idx;
2214 int client_idx;
2215 const struct ipa_gsi_ep_config *gsi_ep_cfg;
Michael Adisumartaf01e9fd2017-08-31 12:23:51 -07002216 int i;
Skylar Chang94692c92017-03-01 09:07:11 -08002217 int ret;
2218 int code = 0;
2219
Michael Adisumarta0090e542018-03-14 10:44:53 -07002220 /* if prod flag is true, then we halt the producer channels also */
Skylar Chang94692c92017-03-01 09:07:11 -08002221 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
Michael Adisumarta0090e542018-03-14 10:44:53 -07002222 if (IPA_CLIENT_IS_Q6_CONS(client_idx)
2223 || (IPA_CLIENT_IS_Q6_PROD(client_idx) && prod)) {
Skylar Chang94692c92017-03-01 09:07:11 -08002224 ep_idx = ipa3_get_ep_mapping(client_idx);
2225 if (ep_idx == -1)
2226 continue;
2227
Skylar Changc1f15312017-05-09 14:14:32 -07002228 gsi_ep_cfg = ipa3_get_gsi_ep_info(client_idx);
Skylar Chang94692c92017-03-01 09:07:11 -08002229 if (!gsi_ep_cfg) {
2230 IPAERR("failed to get GSI config\n");
2231 ipa_assert();
2232 return;
2233 }
2234
2235 ret = gsi_halt_channel_ee(
2236 gsi_ep_cfg->ipa_gsi_chan_num, gsi_ep_cfg->ee,
2237 &code);
Michael Adisumartaf01e9fd2017-08-31 12:23:51 -07002238 for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY &&
2239 ret == -GSI_STATUS_AGAIN; i++) {
2240 IPADBG(
2241 "ch %d ee %d with code %d\n is busy try again",
2242 gsi_ep_cfg->ipa_gsi_chan_num,
2243 gsi_ep_cfg->ee,
2244 code);
2245 usleep_range(IPA_GSI_CHANNEL_HALT_MIN_SLEEP,
2246 IPA_GSI_CHANNEL_HALT_MAX_SLEEP);
2247 ret = gsi_halt_channel_ee(
2248 gsi_ep_cfg->ipa_gsi_chan_num,
2249 gsi_ep_cfg->ee, &code);
2250 }
Skylar Chang94692c92017-03-01 09:07:11 -08002251 if (ret == GSI_STATUS_SUCCESS)
2252 IPADBG("halted gsi ch %d ee %d with code %d\n",
2253 gsi_ep_cfg->ipa_gsi_chan_num,
2254 gsi_ep_cfg->ee,
2255 code);
2256 else
2257 IPAERR("failed to halt ch %d ee %d code %d\n",
2258 gsi_ep_cfg->ipa_gsi_chan_num,
2259 gsi_ep_cfg->ee,
2260 code);
2261 }
2262 }
2263}
2264
Amir Levy9659e592016-10-27 18:08:27 +03002265static int ipa3_q6_clean_q6_flt_tbls(enum ipa_ip_type ip,
2266 enum ipa_rule_type rlt)
2267{
2268 struct ipa3_desc *desc;
2269 struct ipahal_imm_cmd_dma_shared_mem cmd = {0};
2270 struct ipahal_imm_cmd_pyld **cmd_pyld;
2271 int retval = 0;
2272 int pipe_idx;
2273 int flt_idx = 0;
2274 int num_cmds = 0;
2275 int index;
2276 u32 lcl_addr_mem_part;
2277 u32 lcl_hdr_sz;
2278 struct ipa_mem_buffer mem;
2279
2280 IPADBG("Entry\n");
2281
2282 if ((ip >= IPA_IP_MAX) || (rlt >= IPA_RULE_TYPE_MAX)) {
2283 IPAERR("Input Err: ip=%d ; rlt=%d\n", ip, rlt);
2284 return -EINVAL;
2285 }
2286
2287 /* Up to filtering pipes we have filtering tables */
2288 desc = kcalloc(ipa3_ctx->ep_flt_num, sizeof(struct ipa3_desc),
2289 GFP_KERNEL);
2290 if (!desc) {
2291 IPAERR("failed to allocate memory\n");
2292 return -ENOMEM;
2293 }
2294
2295 cmd_pyld = kcalloc(ipa3_ctx->ep_flt_num,
2296 sizeof(struct ipahal_imm_cmd_pyld *), GFP_KERNEL);
2297 if (!cmd_pyld) {
2298 IPAERR("failed to allocate memory\n");
2299 retval = -ENOMEM;
2300 goto free_desc;
2301 }
2302
2303 if (ip == IPA_IP_v4) {
2304 if (rlt == IPA_RULE_HASHABLE) {
2305 lcl_addr_mem_part = IPA_MEM_PART(v4_flt_hash_ofst);
2306 lcl_hdr_sz = IPA_MEM_PART(v4_flt_hash_size);
2307 } else {
2308 lcl_addr_mem_part = IPA_MEM_PART(v4_flt_nhash_ofst);
2309 lcl_hdr_sz = IPA_MEM_PART(v4_flt_nhash_size);
2310 }
2311 } else {
2312 if (rlt == IPA_RULE_HASHABLE) {
2313 lcl_addr_mem_part = IPA_MEM_PART(v6_flt_hash_ofst);
2314 lcl_hdr_sz = IPA_MEM_PART(v6_flt_hash_size);
2315 } else {
2316 lcl_addr_mem_part = IPA_MEM_PART(v6_flt_nhash_ofst);
2317 lcl_hdr_sz = IPA_MEM_PART(v6_flt_nhash_size);
2318 }
2319 }
2320
2321 retval = ipahal_flt_generate_empty_img(1, lcl_hdr_sz, lcl_hdr_sz,
Amir Levy4dc79be2017-02-01 19:18:35 +02002322 0, &mem, true);
Amir Levy9659e592016-10-27 18:08:27 +03002323 if (retval) {
2324 IPAERR("failed to generate flt single tbl empty img\n");
2325 goto free_cmd_pyld;
2326 }
2327
2328 for (pipe_idx = 0; pipe_idx < ipa3_ctx->ipa_num_pipes; pipe_idx++) {
2329 if (!ipa_is_ep_support_flt(pipe_idx))
2330 continue;
2331
2332 /*
2333 * Iterating over all the filtering pipes which are either
2334 * invalid but connected or connected but not configured by AP.
2335 */
2336 if (!ipa3_ctx->ep[pipe_idx].valid ||
2337 ipa3_ctx->ep[pipe_idx].skip_ep_cfg) {
2338
Amir Levy479cfdd2017-10-26 12:23:14 +03002339 if (num_cmds >= ipa3_ctx->ep_flt_num) {
2340 IPAERR("number of commands is out of range\n");
2341 retval = -ENOBUFS;
2342 goto free_empty_img;
2343 }
2344
Amir Levy9659e592016-10-27 18:08:27 +03002345 cmd.is_read = false;
2346 cmd.skip_pipeline_clear = false;
2347 cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2348 cmd.size = mem.size;
2349 cmd.system_addr = mem.phys_base;
2350 cmd.local_addr =
2351 ipa3_ctx->smem_restricted_bytes +
2352 lcl_addr_mem_part +
2353 ipahal_get_hw_tbl_hdr_width() +
2354 flt_idx * ipahal_get_hw_tbl_hdr_width();
2355 cmd_pyld[num_cmds] = ipahal_construct_imm_cmd(
2356 IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
2357 if (!cmd_pyld[num_cmds]) {
2358 IPAERR("fail construct dma_shared_mem cmd\n");
2359 retval = -ENOMEM;
2360 goto free_empty_img;
2361 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002362 ipa3_init_imm_cmd_desc(&desc[num_cmds],
2363 cmd_pyld[num_cmds]);
2364 ++num_cmds;
Amir Levy9659e592016-10-27 18:08:27 +03002365 }
2366
Amir Levy479cfdd2017-10-26 12:23:14 +03002367 ++flt_idx;
Amir Levy9659e592016-10-27 18:08:27 +03002368 }
2369
2370 IPADBG("Sending %d descriptors for flt tbl clearing\n", num_cmds);
2371 retval = ipa3_send_cmd(num_cmds, desc);
2372 if (retval) {
2373 IPAERR("failed to send immediate command (err %d)\n", retval);
2374 retval = -EFAULT;
2375 }
2376
2377free_empty_img:
2378 ipahal_free_dma_mem(&mem);
2379free_cmd_pyld:
2380 for (index = 0; index < num_cmds; index++)
2381 ipahal_destroy_imm_cmd(cmd_pyld[index]);
2382 kfree(cmd_pyld);
2383free_desc:
2384 kfree(desc);
2385 return retval;
2386}
2387
2388static int ipa3_q6_clean_q6_rt_tbls(enum ipa_ip_type ip,
2389 enum ipa_rule_type rlt)
2390{
2391 struct ipa3_desc *desc;
2392 struct ipahal_imm_cmd_dma_shared_mem cmd = {0};
2393 struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
2394 int retval = 0;
2395 u32 modem_rt_index_lo;
2396 u32 modem_rt_index_hi;
2397 u32 lcl_addr_mem_part;
2398 u32 lcl_hdr_sz;
2399 struct ipa_mem_buffer mem;
2400
2401 IPADBG("Entry\n");
2402
2403 if ((ip >= IPA_IP_MAX) || (rlt >= IPA_RULE_TYPE_MAX)) {
2404 IPAERR("Input Err: ip=%d ; rlt=%d\n", ip, rlt);
2405 return -EINVAL;
2406 }
2407
2408 if (ip == IPA_IP_v4) {
2409 modem_rt_index_lo = IPA_MEM_PART(v4_modem_rt_index_lo);
2410 modem_rt_index_hi = IPA_MEM_PART(v4_modem_rt_index_hi);
2411 if (rlt == IPA_RULE_HASHABLE) {
2412 lcl_addr_mem_part = IPA_MEM_PART(v4_rt_hash_ofst);
2413 lcl_hdr_sz = IPA_MEM_PART(v4_flt_hash_size);
2414 } else {
2415 lcl_addr_mem_part = IPA_MEM_PART(v4_rt_nhash_ofst);
2416 lcl_hdr_sz = IPA_MEM_PART(v4_flt_nhash_size);
2417 }
2418 } else {
2419 modem_rt_index_lo = IPA_MEM_PART(v6_modem_rt_index_lo);
2420 modem_rt_index_hi = IPA_MEM_PART(v6_modem_rt_index_hi);
2421 if (rlt == IPA_RULE_HASHABLE) {
2422 lcl_addr_mem_part = IPA_MEM_PART(v6_rt_hash_ofst);
2423 lcl_hdr_sz = IPA_MEM_PART(v6_flt_hash_size);
2424 } else {
2425 lcl_addr_mem_part = IPA_MEM_PART(v6_rt_nhash_ofst);
2426 lcl_hdr_sz = IPA_MEM_PART(v6_flt_nhash_size);
2427 }
2428 }
2429
2430 retval = ipahal_rt_generate_empty_img(
2431 modem_rt_index_hi - modem_rt_index_lo + 1,
Amir Levy4dc79be2017-02-01 19:18:35 +02002432 lcl_hdr_sz, lcl_hdr_sz, &mem, true);
Amir Levy9659e592016-10-27 18:08:27 +03002433 if (retval) {
2434 IPAERR("fail generate empty rt img\n");
2435 return -ENOMEM;
2436 }
2437
2438 desc = kzalloc(sizeof(struct ipa3_desc), GFP_KERNEL);
2439 if (!desc) {
2440 IPAERR("failed to allocate memory\n");
2441 goto free_empty_img;
2442 }
2443
2444 cmd.is_read = false;
2445 cmd.skip_pipeline_clear = false;
2446 cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2447 cmd.size = mem.size;
2448 cmd.system_addr = mem.phys_base;
2449 cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
2450 lcl_addr_mem_part +
2451 modem_rt_index_lo * ipahal_get_hw_tbl_hdr_width();
2452 cmd_pyld = ipahal_construct_imm_cmd(
2453 IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
2454 if (!cmd_pyld) {
2455 IPAERR("failed to construct dma_shared_mem imm cmd\n");
2456 retval = -ENOMEM;
2457 goto free_desc;
2458 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002459 ipa3_init_imm_cmd_desc(desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002460
2461 IPADBG("Sending 1 descriptor for rt tbl clearing\n");
2462 retval = ipa3_send_cmd(1, desc);
2463 if (retval) {
2464 IPAERR("failed to send immediate command (err %d)\n", retval);
2465 retval = -EFAULT;
2466 }
2467
2468 ipahal_destroy_imm_cmd(cmd_pyld);
2469free_desc:
2470 kfree(desc);
2471free_empty_img:
2472 ipahal_free_dma_mem(&mem);
2473 return retval;
2474}
2475
2476static int ipa3_q6_clean_q6_tables(void)
2477{
2478 struct ipa3_desc *desc;
2479 struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
2480 struct ipahal_imm_cmd_register_write reg_write_cmd = {0};
2481 int retval;
2482 struct ipahal_reg_fltrt_hash_flush flush;
2483 struct ipahal_reg_valmask valmask;
2484
2485 IPADBG("Entry\n");
2486
2487
2488 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v4, IPA_RULE_HASHABLE)) {
2489 IPAERR("failed to clean q6 flt tbls (v4/hashable)\n");
2490 return -EFAULT;
2491 }
2492 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v6, IPA_RULE_HASHABLE)) {
2493 IPAERR("failed to clean q6 flt tbls (v6/hashable)\n");
2494 return -EFAULT;
2495 }
2496 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v4, IPA_RULE_NON_HASHABLE)) {
2497 IPAERR("failed to clean q6 flt tbls (v4/non-hashable)\n");
2498 return -EFAULT;
2499 }
2500 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v6, IPA_RULE_NON_HASHABLE)) {
2501 IPAERR("failed to clean q6 flt tbls (v6/non-hashable)\n");
2502 return -EFAULT;
2503 }
2504
2505 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v4, IPA_RULE_HASHABLE)) {
2506 IPAERR("failed to clean q6 rt tbls (v4/hashable)\n");
2507 return -EFAULT;
2508 }
2509 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v6, IPA_RULE_HASHABLE)) {
2510 IPAERR("failed to clean q6 rt tbls (v6/hashable)\n");
2511 return -EFAULT;
2512 }
2513 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v4, IPA_RULE_NON_HASHABLE)) {
2514 IPAERR("failed to clean q6 rt tbls (v4/non-hashable)\n");
2515 return -EFAULT;
2516 }
2517 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v6, IPA_RULE_NON_HASHABLE)) {
2518 IPAERR("failed to clean q6 rt tbls (v6/non-hashable)\n");
2519 return -EFAULT;
2520 }
2521
2522 /* Flush rules cache */
2523 desc = kzalloc(sizeof(struct ipa3_desc), GFP_KERNEL);
2524 if (!desc) {
2525 IPAERR("failed to allocate memory\n");
2526 return -ENOMEM;
2527 }
2528
2529 flush.v4_flt = true;
2530 flush.v4_rt = true;
2531 flush.v6_flt = true;
2532 flush.v6_rt = true;
2533 ipahal_get_fltrt_hash_flush_valmask(&flush, &valmask);
2534 reg_write_cmd.skip_pipeline_clear = false;
2535 reg_write_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2536 reg_write_cmd.offset = ipahal_get_reg_ofst(IPA_FILT_ROUT_HASH_FLUSH);
2537 reg_write_cmd.value = valmask.val;
2538 reg_write_cmd.value_mask = valmask.mask;
2539 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
2540 &reg_write_cmd, false);
2541 if (!cmd_pyld) {
2542 IPAERR("fail construct register_write imm cmd\n");
2543 retval = -EFAULT;
2544 goto bail_desc;
2545 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002546 ipa3_init_imm_cmd_desc(desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002547
2548 IPADBG("Sending 1 descriptor for tbls flush\n");
2549 retval = ipa3_send_cmd(1, desc);
2550 if (retval) {
2551 IPAERR("failed to send immediate command (err %d)\n", retval);
2552 retval = -EFAULT;
2553 }
2554
2555 ipahal_destroy_imm_cmd(cmd_pyld);
2556
2557bail_desc:
2558 kfree(desc);
2559 IPADBG("Done - retval = %d\n", retval);
2560 return retval;
2561}
2562
2563static int ipa3_q6_set_ex_path_to_apps(void)
2564{
2565 int ep_idx;
2566 int client_idx;
2567 struct ipa3_desc *desc;
2568 int num_descs = 0;
2569 int index;
2570 struct ipahal_imm_cmd_register_write reg_write;
2571 struct ipahal_imm_cmd_pyld *cmd_pyld;
2572 int retval;
Amir Levy9659e592016-10-27 18:08:27 +03002573
2574 desc = kcalloc(ipa3_ctx->ipa_num_pipes, sizeof(struct ipa3_desc),
2575 GFP_KERNEL);
2576 if (!desc) {
2577 IPAERR("failed to allocate memory\n");
2578 return -ENOMEM;
2579 }
2580
2581 /* Set the exception path to AP */
2582 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2583 ep_idx = ipa3_get_ep_mapping(client_idx);
2584 if (ep_idx == -1)
2585 continue;
2586
Skylar Chang53137112017-05-12 17:13:13 -07002587 /* disable statuses for all modem controlled prod pipes */
2588 if (IPA_CLIENT_IS_Q6_PROD(client_idx) ||
2589 (ipa3_ctx->ep[ep_idx].valid &&
2590 ipa3_ctx->ep[ep_idx].skip_ep_cfg)) {
Amir Levy5807be32017-04-19 14:35:12 +03002591 ipa_assert_on(num_descs >= ipa3_ctx->ipa_num_pipes);
2592
2593 reg_write.skip_pipeline_clear = false;
2594 reg_write.pipeline_clear_options =
2595 IPAHAL_HPS_CLEAR;
2596 reg_write.offset =
2597 ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n,
2598 ep_idx);
2599 reg_write.value = 0;
2600 reg_write.value_mask = ~0;
2601 cmd_pyld = ipahal_construct_imm_cmd(
2602 IPA_IMM_CMD_REGISTER_WRITE, &reg_write, false);
2603 if (!cmd_pyld) {
2604 IPAERR("fail construct register_write cmd\n");
2605 ipa_assert();
2606 return -EFAULT;
2607 }
2608
Amir Levy479cfdd2017-10-26 12:23:14 +03002609 ipa3_init_imm_cmd_desc(&desc[num_descs], cmd_pyld);
Amir Levy5807be32017-04-19 14:35:12 +03002610 desc[num_descs].callback = ipa3_destroy_imm;
2611 desc[num_descs].user1 = cmd_pyld;
Amir Levy479cfdd2017-10-26 12:23:14 +03002612 ++num_descs;
Amir Levy5807be32017-04-19 14:35:12 +03002613 }
Amir Levy9659e592016-10-27 18:08:27 +03002614 }
2615
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002616 /* Will wait 500msecs for IPA tag process completion */
Amir Levy9659e592016-10-27 18:08:27 +03002617 retval = ipa3_tag_process(desc, num_descs,
2618 msecs_to_jiffies(CLEANUP_TAG_PROCESS_TIMEOUT));
2619 if (retval) {
2620 IPAERR("TAG process failed! (error %d)\n", retval);
2621 /* For timeout error ipa3_destroy_imm cb will destroy user1 */
2622 if (retval != -ETIME) {
2623 for (index = 0; index < num_descs; index++)
2624 if (desc[index].callback)
2625 desc[index].callback(desc[index].user1,
2626 desc[index].user2);
2627 retval = -EINVAL;
2628 }
2629 }
2630
2631 kfree(desc);
2632
2633 return retval;
2634}
2635
2636/**
Skylar Chang68c37d82018-04-07 16:42:36 -07002637 * ipa3_q6_pre_shutdown_cleanup() - A cleanup for all Q6 related configuration
2638 * in IPA HW. This is performed in case of SSR.
2639 *
2640 * This is a mandatory procedure, in case one of the steps fails, the
2641 * AP needs to restart.
2642 */
Amir Levy9659e592016-10-27 18:08:27 +03002643void ipa3_q6_pre_shutdown_cleanup(void)
2644{
2645 IPADBG_LOW("ENTER\n");
2646
2647 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
2648
2649 ipa3_q6_pipe_delay(true);
2650 ipa3_q6_avoid_holb();
2651 if (ipa3_q6_clean_q6_tables()) {
2652 IPAERR("Failed to clean Q6 tables\n");
2653 BUG();
2654 }
2655 if (ipa3_q6_set_ex_path_to_apps()) {
2656 IPAERR("Failed to redirect exceptions to APPS\n");
2657 BUG();
2658 }
2659 /* Remove delay from Q6 PRODs to avoid pending descriptors
Skylar Chang68c37d82018-04-07 16:42:36 -07002660 * on pipe reset procedure
2661 */
Amir Levy9659e592016-10-27 18:08:27 +03002662 ipa3_q6_pipe_delay(false);
2663
2664 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2665 IPADBG_LOW("Exit with success\n");
2666}
2667
2668/*
2669 * ipa3_q6_post_shutdown_cleanup() - As part of this cleanup
2670 * check if GSI channel related to Q6 producer client is empty.
2671 *
2672 * Q6 GSI channel emptiness is needed to garantee no descriptors with invalid
2673 * info are injected into IPA RX from IPA_IF, while modem is restarting.
2674 */
2675void ipa3_q6_post_shutdown_cleanup(void)
2676{
2677 int client_idx;
Skylar Changc1f15312017-05-09 14:14:32 -07002678 int ep_idx;
Michael Adisumarta0090e542018-03-14 10:44:53 -07002679 bool prod = false;
Amir Levy9659e592016-10-27 18:08:27 +03002680
2681 IPADBG_LOW("ENTER\n");
Amir Levy9659e592016-10-27 18:08:27 +03002682
2683 if (!ipa3_ctx->uc_ctx.uc_loaded) {
2684 IPAERR("uC is not loaded. Skipping\n");
2685 return;
2686 }
2687
Skylar Chang94692c92017-03-01 09:07:11 -08002688 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
2689
2690 /* Handle the issue where SUSPEND was removed for some reason */
2691 ipa3_q6_avoid_holb();
Michael Adisumarta0090e542018-03-14 10:44:53 -07002692
2693 /* halt both prod and cons channels starting at IPAv4 */
2694 if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
2695 prod = true;
2696 ipa3_halt_q6_gsi_channels(prod);
2697 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2698 IPADBG("Exit without consumer check\n");
2699 return;
2700 }
2701
2702 ipa3_halt_q6_gsi_channels(prod);
Skylar Chang94692c92017-03-01 09:07:11 -08002703
Amir Levy9659e592016-10-27 18:08:27 +03002704 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
2705 if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
Skylar Changc1f15312017-05-09 14:14:32 -07002706 ep_idx = ipa3_get_ep_mapping(client_idx);
2707 if (ep_idx == -1)
2708 continue;
2709
Amir Levy9659e592016-10-27 18:08:27 +03002710 if (ipa3_uc_is_gsi_channel_empty(client_idx)) {
2711 IPAERR("fail to validate Q6 ch emptiness %d\n",
2712 client_idx);
2713 BUG();
2714 return;
2715 }
2716 }
2717
2718 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2719 IPADBG_LOW("Exit with success\n");
2720}
2721
2722static inline void ipa3_sram_set_canary(u32 *sram_mmio, int offset)
2723{
2724 /* Set 4 bytes of CANARY before the offset */
2725 sram_mmio[(offset - 4) / 4] = IPA_MEM_CANARY_VAL;
2726}
2727
2728/**
Amir Levy9fadeca2017-04-25 10:18:32 +03002729 * _ipa_init_sram_v3() - Initialize IPA local SRAM.
Amir Levy9659e592016-10-27 18:08:27 +03002730 *
2731 * Return codes: 0 for success, negative value for failure
2732 */
Amir Levy9fadeca2017-04-25 10:18:32 +03002733int _ipa_init_sram_v3(void)
Amir Levy9659e592016-10-27 18:08:27 +03002734{
2735 u32 *ipa_sram_mmio;
2736 unsigned long phys_addr;
2737
2738 phys_addr = ipa3_ctx->ipa_wrapper_base +
2739 ipa3_ctx->ctrl->ipa_reg_base_ofst +
2740 ipahal_get_reg_n_ofst(IPA_SRAM_DIRECT_ACCESS_n,
2741 ipa3_ctx->smem_restricted_bytes / 4);
2742
2743 ipa_sram_mmio = ioremap(phys_addr, ipa3_ctx->smem_sz);
2744 if (!ipa_sram_mmio) {
2745 IPAERR("fail to ioremap IPA SRAM\n");
2746 return -ENOMEM;
2747 }
2748
2749 /* Consult with ipa_i.h on the location of the CANARY values */
2750 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_flt_hash_ofst) - 4);
2751 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_flt_hash_ofst));
2752 ipa3_sram_set_canary(ipa_sram_mmio,
2753 IPA_MEM_PART(v4_flt_nhash_ofst) - 4);
2754 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_flt_nhash_ofst));
2755 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_flt_hash_ofst) - 4);
2756 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_flt_hash_ofst));
2757 ipa3_sram_set_canary(ipa_sram_mmio,
2758 IPA_MEM_PART(v6_flt_nhash_ofst) - 4);
2759 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_flt_nhash_ofst));
2760 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_hash_ofst) - 4);
2761 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_hash_ofst));
2762 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_nhash_ofst) - 4);
2763 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_nhash_ofst));
2764 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_hash_ofst) - 4);
2765 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_hash_ofst));
2766 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_nhash_ofst) - 4);
2767 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_nhash_ofst));
2768 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_hdr_ofst) - 4);
2769 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_hdr_ofst));
2770 ipa3_sram_set_canary(ipa_sram_mmio,
2771 IPA_MEM_PART(modem_hdr_proc_ctx_ofst) - 4);
2772 ipa3_sram_set_canary(ipa_sram_mmio,
2773 IPA_MEM_PART(modem_hdr_proc_ctx_ofst));
2774 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_ofst) - 4);
2775 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_ofst));
Amir Levy9fadeca2017-04-25 10:18:32 +03002776 ipa3_sram_set_canary(ipa_sram_mmio,
2777 (ipa_get_hw_type() >= IPA_HW_v3_5) ?
2778 IPA_MEM_PART(uc_event_ring_ofst) :
2779 IPA_MEM_PART(end_ofst));
Amir Levy9659e592016-10-27 18:08:27 +03002780
2781 iounmap(ipa_sram_mmio);
2782
2783 return 0;
2784}
2785
2786/**
2787 * _ipa_init_hdr_v3_0() - Initialize IPA header block.
2788 *
2789 * Return codes: 0 for success, negative value for failure
2790 */
2791int _ipa_init_hdr_v3_0(void)
2792{
Amir Levy479cfdd2017-10-26 12:23:14 +03002793 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03002794 struct ipa_mem_buffer mem;
2795 struct ipahal_imm_cmd_hdr_init_local cmd = {0};
2796 struct ipahal_imm_cmd_pyld *cmd_pyld;
2797 struct ipahal_imm_cmd_dma_shared_mem dma_cmd = { 0 };
2798
2799 mem.size = IPA_MEM_PART(modem_hdr_size) + IPA_MEM_PART(apps_hdr_size);
2800 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size, &mem.phys_base,
2801 GFP_KERNEL);
2802 if (!mem.base) {
2803 IPAERR("fail to alloc DMA buff of size %d\n", mem.size);
2804 return -ENOMEM;
2805 }
2806 memset(mem.base, 0, mem.size);
2807
2808 cmd.hdr_table_addr = mem.phys_base;
2809 cmd.size_hdr_table = mem.size;
2810 cmd.hdr_addr = ipa3_ctx->smem_restricted_bytes +
2811 IPA_MEM_PART(modem_hdr_ofst);
2812 cmd_pyld = ipahal_construct_imm_cmd(
2813 IPA_IMM_CMD_HDR_INIT_LOCAL, &cmd, false);
2814 if (!cmd_pyld) {
2815 IPAERR("fail to construct hdr_init_local imm cmd\n");
2816 dma_free_coherent(ipa3_ctx->pdev,
2817 mem.size, mem.base,
2818 mem.phys_base);
2819 return -EFAULT;
2820 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002821 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002822 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
2823
2824 if (ipa3_send_cmd(1, &desc)) {
2825 IPAERR("fail to send immediate command\n");
2826 ipahal_destroy_imm_cmd(cmd_pyld);
2827 dma_free_coherent(ipa3_ctx->pdev,
2828 mem.size, mem.base,
2829 mem.phys_base);
2830 return -EFAULT;
2831 }
2832
2833 ipahal_destroy_imm_cmd(cmd_pyld);
2834 dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
2835
2836 mem.size = IPA_MEM_PART(modem_hdr_proc_ctx_size) +
2837 IPA_MEM_PART(apps_hdr_proc_ctx_size);
2838 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size, &mem.phys_base,
2839 GFP_KERNEL);
2840 if (!mem.base) {
2841 IPAERR("fail to alloc DMA buff of size %d\n", mem.size);
2842 return -ENOMEM;
2843 }
2844 memset(mem.base, 0, mem.size);
Amir Levy9659e592016-10-27 18:08:27 +03002845
2846 dma_cmd.is_read = false;
2847 dma_cmd.skip_pipeline_clear = false;
2848 dma_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2849 dma_cmd.system_addr = mem.phys_base;
2850 dma_cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
2851 IPA_MEM_PART(modem_hdr_proc_ctx_ofst);
2852 dma_cmd.size = mem.size;
2853 cmd_pyld = ipahal_construct_imm_cmd(
2854 IPA_IMM_CMD_DMA_SHARED_MEM, &dma_cmd, false);
2855 if (!cmd_pyld) {
2856 IPAERR("fail to construct dma_shared_mem imm\n");
2857 dma_free_coherent(ipa3_ctx->pdev,
2858 mem.size, mem.base,
2859 mem.phys_base);
2860 return -EFAULT;
2861 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002862 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002863 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
2864
2865 if (ipa3_send_cmd(1, &desc)) {
2866 IPAERR("fail to send immediate command\n");
2867 ipahal_destroy_imm_cmd(cmd_pyld);
2868 dma_free_coherent(ipa3_ctx->pdev,
2869 mem.size,
2870 mem.base,
2871 mem.phys_base);
2872 return -EFAULT;
2873 }
2874 ipahal_destroy_imm_cmd(cmd_pyld);
2875
2876 ipahal_write_reg(IPA_LOCAL_PKT_PROC_CNTXT_BASE, dma_cmd.local_addr);
2877
2878 dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
2879
2880 return 0;
2881}
2882
2883/**
2884 * _ipa_init_rt4_v3() - Initialize IPA routing block for IPv4.
2885 *
2886 * Return codes: 0 for success, negative value for failure
2887 */
2888int _ipa_init_rt4_v3(void)
2889{
Amir Levy479cfdd2017-10-26 12:23:14 +03002890 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03002891 struct ipa_mem_buffer mem;
2892 struct ipahal_imm_cmd_ip_v4_routing_init v4_cmd;
2893 struct ipahal_imm_cmd_pyld *cmd_pyld;
2894 int i;
2895 int rc = 0;
2896
2897 for (i = IPA_MEM_PART(v4_modem_rt_index_lo);
2898 i <= IPA_MEM_PART(v4_modem_rt_index_hi);
2899 i++)
2900 ipa3_ctx->rt_idx_bitmap[IPA_IP_v4] |= (1 << i);
2901 IPADBG("v4 rt bitmap 0x%lx\n", ipa3_ctx->rt_idx_bitmap[IPA_IP_v4]);
2902
2903 rc = ipahal_rt_generate_empty_img(IPA_MEM_PART(v4_rt_num_index),
2904 IPA_MEM_PART(v4_rt_hash_size), IPA_MEM_PART(v4_rt_nhash_size),
Amir Levy4dc79be2017-02-01 19:18:35 +02002905 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03002906 if (rc) {
2907 IPAERR("fail generate empty v4 rt img\n");
2908 return rc;
2909 }
2910
2911 v4_cmd.hash_rules_addr = mem.phys_base;
2912 v4_cmd.hash_rules_size = mem.size;
2913 v4_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
2914 IPA_MEM_PART(v4_rt_hash_ofst);
2915 v4_cmd.nhash_rules_addr = mem.phys_base;
2916 v4_cmd.nhash_rules_size = mem.size;
2917 v4_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
2918 IPA_MEM_PART(v4_rt_nhash_ofst);
2919 IPADBG("putting hashable routing IPv4 rules to phys 0x%x\n",
2920 v4_cmd.hash_local_addr);
2921 IPADBG("putting non-hashable routing IPv4 rules to phys 0x%x\n",
2922 v4_cmd.nhash_local_addr);
2923 cmd_pyld = ipahal_construct_imm_cmd(
2924 IPA_IMM_CMD_IP_V4_ROUTING_INIT, &v4_cmd, false);
2925 if (!cmd_pyld) {
2926 IPAERR("fail construct ip_v4_rt_init imm cmd\n");
2927 rc = -EPERM;
2928 goto free_mem;
2929 }
2930
Amir Levy479cfdd2017-10-26 12:23:14 +03002931 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002932 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
2933
2934 if (ipa3_send_cmd(1, &desc)) {
2935 IPAERR("fail to send immediate command\n");
2936 rc = -EFAULT;
2937 }
2938
2939 ipahal_destroy_imm_cmd(cmd_pyld);
2940
2941free_mem:
2942 ipahal_free_dma_mem(&mem);
2943 return rc;
2944}
2945
2946/**
2947 * _ipa_init_rt6_v3() - Initialize IPA routing block for IPv6.
2948 *
2949 * Return codes: 0 for success, negative value for failure
2950 */
2951int _ipa_init_rt6_v3(void)
2952{
Amir Levy479cfdd2017-10-26 12:23:14 +03002953 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03002954 struct ipa_mem_buffer mem;
2955 struct ipahal_imm_cmd_ip_v6_routing_init v6_cmd;
2956 struct ipahal_imm_cmd_pyld *cmd_pyld;
2957 int i;
2958 int rc = 0;
2959
2960 for (i = IPA_MEM_PART(v6_modem_rt_index_lo);
2961 i <= IPA_MEM_PART(v6_modem_rt_index_hi);
2962 i++)
2963 ipa3_ctx->rt_idx_bitmap[IPA_IP_v6] |= (1 << i);
2964 IPADBG("v6 rt bitmap 0x%lx\n", ipa3_ctx->rt_idx_bitmap[IPA_IP_v6]);
2965
2966 rc = ipahal_rt_generate_empty_img(IPA_MEM_PART(v6_rt_num_index),
2967 IPA_MEM_PART(v6_rt_hash_size), IPA_MEM_PART(v6_rt_nhash_size),
Amir Levy4dc79be2017-02-01 19:18:35 +02002968 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03002969 if (rc) {
2970 IPAERR("fail generate empty v6 rt img\n");
2971 return rc;
2972 }
2973
2974 v6_cmd.hash_rules_addr = mem.phys_base;
2975 v6_cmd.hash_rules_size = mem.size;
2976 v6_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
2977 IPA_MEM_PART(v6_rt_hash_ofst);
2978 v6_cmd.nhash_rules_addr = mem.phys_base;
2979 v6_cmd.nhash_rules_size = mem.size;
2980 v6_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
2981 IPA_MEM_PART(v6_rt_nhash_ofst);
2982 IPADBG("putting hashable routing IPv6 rules to phys 0x%x\n",
2983 v6_cmd.hash_local_addr);
2984 IPADBG("putting non-hashable routing IPv6 rules to phys 0x%x\n",
2985 v6_cmd.nhash_local_addr);
2986 cmd_pyld = ipahal_construct_imm_cmd(
2987 IPA_IMM_CMD_IP_V6_ROUTING_INIT, &v6_cmd, false);
2988 if (!cmd_pyld) {
2989 IPAERR("fail construct ip_v6_rt_init imm cmd\n");
2990 rc = -EPERM;
2991 goto free_mem;
2992 }
2993
Amir Levy479cfdd2017-10-26 12:23:14 +03002994 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002995 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
2996
2997 if (ipa3_send_cmd(1, &desc)) {
2998 IPAERR("fail to send immediate command\n");
2999 rc = -EFAULT;
3000 }
3001
3002 ipahal_destroy_imm_cmd(cmd_pyld);
3003
3004free_mem:
3005 ipahal_free_dma_mem(&mem);
3006 return rc;
3007}
3008
3009/**
3010 * _ipa_init_flt4_v3() - Initialize IPA filtering block for IPv4.
3011 *
3012 * Return codes: 0 for success, negative value for failure
3013 */
3014int _ipa_init_flt4_v3(void)
3015{
Amir Levy479cfdd2017-10-26 12:23:14 +03003016 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03003017 struct ipa_mem_buffer mem;
3018 struct ipahal_imm_cmd_ip_v4_filter_init v4_cmd;
3019 struct ipahal_imm_cmd_pyld *cmd_pyld;
3020 int rc;
3021
3022 rc = ipahal_flt_generate_empty_img(ipa3_ctx->ep_flt_num,
3023 IPA_MEM_PART(v4_flt_hash_size),
3024 IPA_MEM_PART(v4_flt_nhash_size), ipa3_ctx->ep_flt_bitmap,
Amir Levy4dc79be2017-02-01 19:18:35 +02003025 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03003026 if (rc) {
3027 IPAERR("fail generate empty v4 flt img\n");
3028 return rc;
3029 }
3030
3031 v4_cmd.hash_rules_addr = mem.phys_base;
3032 v4_cmd.hash_rules_size = mem.size;
3033 v4_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
3034 IPA_MEM_PART(v4_flt_hash_ofst);
3035 v4_cmd.nhash_rules_addr = mem.phys_base;
3036 v4_cmd.nhash_rules_size = mem.size;
3037 v4_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
3038 IPA_MEM_PART(v4_flt_nhash_ofst);
3039 IPADBG("putting hashable filtering IPv4 rules to phys 0x%x\n",
3040 v4_cmd.hash_local_addr);
3041 IPADBG("putting non-hashable filtering IPv4 rules to phys 0x%x\n",
3042 v4_cmd.nhash_local_addr);
3043 cmd_pyld = ipahal_construct_imm_cmd(
3044 IPA_IMM_CMD_IP_V4_FILTER_INIT, &v4_cmd, false);
3045 if (!cmd_pyld) {
3046 IPAERR("fail construct ip_v4_flt_init imm cmd\n");
3047 rc = -EPERM;
3048 goto free_mem;
3049 }
3050
Amir Levy479cfdd2017-10-26 12:23:14 +03003051 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03003052 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
3053
3054 if (ipa3_send_cmd(1, &desc)) {
3055 IPAERR("fail to send immediate command\n");
3056 rc = -EFAULT;
3057 }
3058
3059 ipahal_destroy_imm_cmd(cmd_pyld);
3060
3061free_mem:
3062 ipahal_free_dma_mem(&mem);
3063 return rc;
3064}
3065
3066/**
3067 * _ipa_init_flt6_v3() - Initialize IPA filtering block for IPv6.
3068 *
3069 * Return codes: 0 for success, negative value for failure
3070 */
3071int _ipa_init_flt6_v3(void)
3072{
Amir Levy479cfdd2017-10-26 12:23:14 +03003073 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03003074 struct ipa_mem_buffer mem;
3075 struct ipahal_imm_cmd_ip_v6_filter_init v6_cmd;
3076 struct ipahal_imm_cmd_pyld *cmd_pyld;
3077 int rc;
3078
3079 rc = ipahal_flt_generate_empty_img(ipa3_ctx->ep_flt_num,
3080 IPA_MEM_PART(v6_flt_hash_size),
3081 IPA_MEM_PART(v6_flt_nhash_size), ipa3_ctx->ep_flt_bitmap,
Amir Levy4dc79be2017-02-01 19:18:35 +02003082 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03003083 if (rc) {
3084 IPAERR("fail generate empty v6 flt img\n");
3085 return rc;
3086 }
3087
3088 v6_cmd.hash_rules_addr = mem.phys_base;
3089 v6_cmd.hash_rules_size = mem.size;
3090 v6_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
3091 IPA_MEM_PART(v6_flt_hash_ofst);
3092 v6_cmd.nhash_rules_addr = mem.phys_base;
3093 v6_cmd.nhash_rules_size = mem.size;
3094 v6_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
3095 IPA_MEM_PART(v6_flt_nhash_ofst);
3096 IPADBG("putting hashable filtering IPv6 rules to phys 0x%x\n",
3097 v6_cmd.hash_local_addr);
3098 IPADBG("putting non-hashable filtering IPv6 rules to phys 0x%x\n",
3099 v6_cmd.nhash_local_addr);
3100
3101 cmd_pyld = ipahal_construct_imm_cmd(
3102 IPA_IMM_CMD_IP_V6_FILTER_INIT, &v6_cmd, false);
3103 if (!cmd_pyld) {
3104 IPAERR("fail construct ip_v6_flt_init imm cmd\n");
3105 rc = -EPERM;
3106 goto free_mem;
3107 }
3108
Amir Levy479cfdd2017-10-26 12:23:14 +03003109 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03003110 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
3111
3112 if (ipa3_send_cmd(1, &desc)) {
3113 IPAERR("fail to send immediate command\n");
3114 rc = -EFAULT;
3115 }
3116
3117 ipahal_destroy_imm_cmd(cmd_pyld);
3118
3119free_mem:
3120 ipahal_free_dma_mem(&mem);
3121 return rc;
3122}
3123
3124static int ipa3_setup_flt_hash_tuple(void)
3125{
3126 int pipe_idx;
3127 struct ipahal_reg_hash_tuple tuple;
3128
3129 memset(&tuple, 0, sizeof(struct ipahal_reg_hash_tuple));
3130
3131 for (pipe_idx = 0; pipe_idx < ipa3_ctx->ipa_num_pipes ; pipe_idx++) {
3132 if (!ipa_is_ep_support_flt(pipe_idx))
3133 continue;
3134
3135 if (ipa_is_modem_pipe(pipe_idx))
3136 continue;
3137
3138 if (ipa3_set_flt_tuple_mask(pipe_idx, &tuple)) {
3139 IPAERR("failed to setup pipe %d flt tuple\n", pipe_idx);
3140 return -EFAULT;
3141 }
3142 }
3143
3144 return 0;
3145}
3146
3147static int ipa3_setup_rt_hash_tuple(void)
3148{
3149 int tbl_idx;
3150 struct ipahal_reg_hash_tuple tuple;
3151
3152 memset(&tuple, 0, sizeof(struct ipahal_reg_hash_tuple));
3153
3154 for (tbl_idx = 0;
3155 tbl_idx < max(IPA_MEM_PART(v6_rt_num_index),
3156 IPA_MEM_PART(v4_rt_num_index));
3157 tbl_idx++) {
3158
3159 if (tbl_idx >= IPA_MEM_PART(v4_modem_rt_index_lo) &&
3160 tbl_idx <= IPA_MEM_PART(v4_modem_rt_index_hi))
3161 continue;
3162
3163 if (tbl_idx >= IPA_MEM_PART(v6_modem_rt_index_lo) &&
3164 tbl_idx <= IPA_MEM_PART(v6_modem_rt_index_hi))
3165 continue;
3166
3167 if (ipa3_set_rt_tuple_mask(tbl_idx, &tuple)) {
3168 IPAERR("failed to setup tbl %d rt tuple\n", tbl_idx);
3169 return -EFAULT;
3170 }
3171 }
3172
3173 return 0;
3174}
3175
3176static int ipa3_setup_apps_pipes(void)
3177{
3178 struct ipa_sys_connect_params sys_in;
3179 int result = 0;
3180
3181 if (ipa3_ctx->gsi_ch20_wa) {
3182 IPADBG("Allocating GSI physical channel 20\n");
3183 result = ipa_gsi_ch20_wa();
3184 if (result) {
3185 IPAERR("ipa_gsi_ch20_wa failed %d\n", result);
Ghanim Fodic6b67492017-03-15 14:19:56 +02003186 goto fail_ch20_wa;
Amir Levy9659e592016-10-27 18:08:27 +03003187 }
3188 }
3189
Skylar Changd407e592017-03-30 11:25:30 -07003190 /* allocate the common PROD event ring */
3191 if (ipa3_alloc_common_event_ring()) {
3192 IPAERR("ipa3_alloc_common_event_ring failed.\n");
3193 result = -EPERM;
3194 goto fail_ch20_wa;
3195 }
3196
Amir Levy9659e592016-10-27 18:08:27 +03003197 /* CMD OUT (AP->IPA) */
3198 memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
3199 sys_in.client = IPA_CLIENT_APPS_CMD_PROD;
3200 sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
3201 sys_in.ipa_ep_cfg.mode.mode = IPA_DMA;
3202 sys_in.ipa_ep_cfg.mode.dst = IPA_CLIENT_APPS_LAN_CONS;
3203 if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_cmd)) {
Ghanim Fodic6b67492017-03-15 14:19:56 +02003204 IPAERR(":setup sys pipe (APPS_CMD_PROD) failed.\n");
Amir Levy9659e592016-10-27 18:08:27 +03003205 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003206 goto fail_ch20_wa;
Amir Levy9659e592016-10-27 18:08:27 +03003207 }
3208 IPADBG("Apps to IPA cmd pipe is connected\n");
3209
3210 ipa3_ctx->ctrl->ipa_init_sram();
3211 IPADBG("SRAM initialized\n");
3212
3213 ipa3_ctx->ctrl->ipa_init_hdr();
3214 IPADBG("HDR initialized\n");
3215
3216 ipa3_ctx->ctrl->ipa_init_rt4();
3217 IPADBG("V4 RT initialized\n");
3218
3219 ipa3_ctx->ctrl->ipa_init_rt6();
3220 IPADBG("V6 RT initialized\n");
3221
3222 ipa3_ctx->ctrl->ipa_init_flt4();
3223 IPADBG("V4 FLT initialized\n");
3224
3225 ipa3_ctx->ctrl->ipa_init_flt6();
3226 IPADBG("V6 FLT initialized\n");
3227
3228 if (ipa3_setup_flt_hash_tuple()) {
3229 IPAERR(":fail to configure flt hash tuple\n");
3230 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003231 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003232 }
3233 IPADBG("flt hash tuple is configured\n");
3234
3235 if (ipa3_setup_rt_hash_tuple()) {
3236 IPAERR(":fail to configure rt hash tuple\n");
3237 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003238 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003239 }
3240 IPADBG("rt hash tuple is configured\n");
3241
3242 if (ipa3_setup_exception_path()) {
3243 IPAERR(":fail to setup excp path\n");
3244 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003245 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003246 }
3247 IPADBG("Exception path was successfully set");
3248
3249 if (ipa3_setup_dflt_rt_tables()) {
3250 IPAERR(":fail to setup dflt routes\n");
3251 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003252 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003253 }
3254 IPADBG("default routing was set\n");
3255
Ghanim Fodic6b67492017-03-15 14:19:56 +02003256 /* LAN IN (IPA->AP) */
Amir Levy9659e592016-10-27 18:08:27 +03003257 memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
3258 sys_in.client = IPA_CLIENT_APPS_LAN_CONS;
3259 sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
3260 sys_in.notify = ipa3_lan_rx_cb;
3261 sys_in.priv = NULL;
3262 sys_in.ipa_ep_cfg.hdr.hdr_len = IPA_LAN_RX_HEADER_LENGTH;
3263 sys_in.ipa_ep_cfg.hdr_ext.hdr_little_endian = false;
3264 sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid = true;
3265 sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad = IPA_HDR_PAD;
3266 sys_in.ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = false;
3267 sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 0;
3268 sys_in.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2;
3269 sys_in.ipa_ep_cfg.cfg.cs_offload_en = IPA_ENABLE_CS_OFFLOAD_DL;
3270
3271 /**
3272 * ipa_lan_rx_cb() intended to notify the source EP about packet
3273 * being received on the LAN_CONS via calling the source EP call-back.
3274 * There could be a race condition with calling this call-back. Other
3275 * thread may nullify it - e.g. on EP disconnect.
3276 * This lock intended to protect the access to the source EP call-back
3277 */
3278 spin_lock_init(&ipa3_ctx->disconnect_lock);
3279 if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_data_in)) {
Ghanim Fodic6b67492017-03-15 14:19:56 +02003280 IPAERR(":setup sys pipe (LAN_CONS) failed.\n");
Amir Levy9659e592016-10-27 18:08:27 +03003281 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003282 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003283 }
3284
Ghanim Fodic6b67492017-03-15 14:19:56 +02003285 /* LAN OUT (AP->IPA) */
Amir Levy54fe4d32017-03-16 11:21:49 +02003286 if (!ipa3_ctx->ipa_config_is_mhi) {
3287 memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
3288 sys_in.client = IPA_CLIENT_APPS_LAN_PROD;
3289 sys_in.desc_fifo_sz = IPA_SYS_TX_DATA_DESC_FIFO_SZ;
3290 sys_in.ipa_ep_cfg.mode.mode = IPA_BASIC;
3291 if (ipa3_setup_sys_pipe(&sys_in,
3292 &ipa3_ctx->clnt_hdl_data_out)) {
3293 IPAERR(":setup sys pipe (LAN_PROD) failed.\n");
3294 result = -EPERM;
3295 goto fail_lan_data_out;
3296 }
Amir Levy9659e592016-10-27 18:08:27 +03003297 }
3298
3299 return 0;
3300
Ghanim Fodic6b67492017-03-15 14:19:56 +02003301fail_lan_data_out:
Amir Levy9659e592016-10-27 18:08:27 +03003302 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_in);
Ghanim Fodic6b67492017-03-15 14:19:56 +02003303fail_flt_hash_tuple:
Amir Levy9659e592016-10-27 18:08:27 +03003304 if (ipa3_ctx->dflt_v6_rt_rule_hdl)
3305 __ipa3_del_rt_rule(ipa3_ctx->dflt_v6_rt_rule_hdl);
3306 if (ipa3_ctx->dflt_v4_rt_rule_hdl)
3307 __ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl);
3308 if (ipa3_ctx->excp_hdr_hdl)
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02003309 __ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03003310 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
Ghanim Fodic6b67492017-03-15 14:19:56 +02003311fail_ch20_wa:
Amir Levy9659e592016-10-27 18:08:27 +03003312 return result;
3313}
3314
3315static void ipa3_teardown_apps_pipes(void)
3316{
Amir Levy54fe4d32017-03-16 11:21:49 +02003317 if (!ipa3_ctx->ipa_config_is_mhi)
3318 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_out);
Amir Levy9659e592016-10-27 18:08:27 +03003319 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_in);
3320 __ipa3_del_rt_rule(ipa3_ctx->dflt_v6_rt_rule_hdl);
3321 __ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl);
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02003322 __ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03003323 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
3324}
3325
3326#ifdef CONFIG_COMPAT
Amir Levy479cfdd2017-10-26 12:23:14 +03003327
3328static long compat_ipa3_nat_ipv6ct_alloc_table(unsigned long arg,
3329 int (alloc_func)(struct ipa_ioc_nat_ipv6ct_table_alloc *))
3330{
3331 long retval;
3332 struct ipa_ioc_nat_ipv6ct_table_alloc32 table_alloc32;
3333 struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc;
3334
3335 retval = copy_from_user(&table_alloc32, (const void __user *)arg,
3336 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32));
3337 if (retval)
3338 return retval;
3339
3340 table_alloc.size = (size_t)table_alloc32.size;
3341 table_alloc.offset = (off_t)table_alloc32.offset;
3342
3343 retval = alloc_func(&table_alloc);
3344 if (retval)
3345 return retval;
3346
3347 if (table_alloc.offset) {
3348 table_alloc32.offset = (compat_off_t)table_alloc.offset;
3349 retval = copy_to_user((void __user *)arg, &table_alloc32,
3350 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32));
3351 }
3352
3353 return retval;
3354}
3355
Amir Levy9659e592016-10-27 18:08:27 +03003356long compat_ipa3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
3357{
Amir Levy479cfdd2017-10-26 12:23:14 +03003358 long retval = 0;
Amir Levy9659e592016-10-27 18:08:27 +03003359 struct ipa3_ioc_nat_alloc_mem32 nat_mem32;
3360 struct ipa_ioc_nat_alloc_mem nat_mem;
3361
3362 switch (cmd) {
3363 case IPA_IOC_ADD_HDR32:
3364 cmd = IPA_IOC_ADD_HDR;
3365 break;
3366 case IPA_IOC_DEL_HDR32:
3367 cmd = IPA_IOC_DEL_HDR;
3368 break;
3369 case IPA_IOC_ADD_RT_RULE32:
3370 cmd = IPA_IOC_ADD_RT_RULE;
3371 break;
3372 case IPA_IOC_DEL_RT_RULE32:
3373 cmd = IPA_IOC_DEL_RT_RULE;
3374 break;
3375 case IPA_IOC_ADD_FLT_RULE32:
3376 cmd = IPA_IOC_ADD_FLT_RULE;
3377 break;
3378 case IPA_IOC_DEL_FLT_RULE32:
3379 cmd = IPA_IOC_DEL_FLT_RULE;
3380 break;
3381 case IPA_IOC_GET_RT_TBL32:
3382 cmd = IPA_IOC_GET_RT_TBL;
3383 break;
3384 case IPA_IOC_COPY_HDR32:
3385 cmd = IPA_IOC_COPY_HDR;
3386 break;
3387 case IPA_IOC_QUERY_INTF32:
3388 cmd = IPA_IOC_QUERY_INTF;
3389 break;
3390 case IPA_IOC_QUERY_INTF_TX_PROPS32:
3391 cmd = IPA_IOC_QUERY_INTF_TX_PROPS;
3392 break;
3393 case IPA_IOC_QUERY_INTF_RX_PROPS32:
3394 cmd = IPA_IOC_QUERY_INTF_RX_PROPS;
3395 break;
3396 case IPA_IOC_QUERY_INTF_EXT_PROPS32:
3397 cmd = IPA_IOC_QUERY_INTF_EXT_PROPS;
3398 break;
3399 case IPA_IOC_GET_HDR32:
3400 cmd = IPA_IOC_GET_HDR;
3401 break;
3402 case IPA_IOC_ALLOC_NAT_MEM32:
Amir Levy479cfdd2017-10-26 12:23:14 +03003403 retval = copy_from_user(&nat_mem32, (const void __user *)arg,
3404 sizeof(struct ipa3_ioc_nat_alloc_mem32));
3405 if (retval)
3406 return retval;
Amir Levy9659e592016-10-27 18:08:27 +03003407 memcpy(nat_mem.dev_name, nat_mem32.dev_name,
3408 IPA_RESOURCE_NAME_MAX);
3409 nat_mem.size = (size_t)nat_mem32.size;
3410 nat_mem.offset = (off_t)nat_mem32.offset;
3411
3412 /* null terminate the string */
3413 nat_mem.dev_name[IPA_RESOURCE_NAME_MAX - 1] = '\0';
3414
Amir Levy479cfdd2017-10-26 12:23:14 +03003415 retval = ipa3_allocate_nat_device(&nat_mem);
3416 if (retval)
3417 return retval;
Amir Levy9659e592016-10-27 18:08:27 +03003418 nat_mem32.offset = (compat_off_t)nat_mem.offset;
Amir Levy479cfdd2017-10-26 12:23:14 +03003419 retval = copy_to_user((void __user *)arg, &nat_mem32,
3420 sizeof(struct ipa3_ioc_nat_alloc_mem32));
Amir Levy9659e592016-10-27 18:08:27 +03003421 return retval;
Amir Levy479cfdd2017-10-26 12:23:14 +03003422 case IPA_IOC_ALLOC_NAT_TABLE32:
3423 return compat_ipa3_nat_ipv6ct_alloc_table(arg,
3424 ipa3_allocate_nat_table);
3425 case IPA_IOC_ALLOC_IPV6CT_TABLE32:
3426 return compat_ipa3_nat_ipv6ct_alloc_table(arg,
3427 ipa3_allocate_ipv6ct_table);
Amir Levy9659e592016-10-27 18:08:27 +03003428 case IPA_IOC_V4_INIT_NAT32:
3429 cmd = IPA_IOC_V4_INIT_NAT;
3430 break;
Amir Levy479cfdd2017-10-26 12:23:14 +03003431 case IPA_IOC_INIT_IPV6CT_TABLE32:
3432 cmd = IPA_IOC_INIT_IPV6CT_TABLE;
3433 break;
3434 case IPA_IOC_TABLE_DMA_CMD32:
3435 cmd = IPA_IOC_TABLE_DMA_CMD;
Amir Levy9659e592016-10-27 18:08:27 +03003436 break;
3437 case IPA_IOC_V4_DEL_NAT32:
3438 cmd = IPA_IOC_V4_DEL_NAT;
3439 break;
Amir Levy479cfdd2017-10-26 12:23:14 +03003440 case IPA_IOC_DEL_NAT_TABLE32:
3441 cmd = IPA_IOC_DEL_NAT_TABLE;
3442 break;
3443 case IPA_IOC_DEL_IPV6CT_TABLE32:
3444 cmd = IPA_IOC_DEL_IPV6CT_TABLE;
3445 break;
3446 case IPA_IOC_NAT_MODIFY_PDN32:
3447 cmd = IPA_IOC_NAT_MODIFY_PDN;
3448 break;
Amir Levy9659e592016-10-27 18:08:27 +03003449 case IPA_IOC_GET_NAT_OFFSET32:
3450 cmd = IPA_IOC_GET_NAT_OFFSET;
3451 break;
3452 case IPA_IOC_PULL_MSG32:
3453 cmd = IPA_IOC_PULL_MSG;
3454 break;
3455 case IPA_IOC_RM_ADD_DEPENDENCY32:
3456 cmd = IPA_IOC_RM_ADD_DEPENDENCY;
3457 break;
3458 case IPA_IOC_RM_DEL_DEPENDENCY32:
3459 cmd = IPA_IOC_RM_DEL_DEPENDENCY;
3460 break;
3461 case IPA_IOC_GENERATE_FLT_EQ32:
3462 cmd = IPA_IOC_GENERATE_FLT_EQ;
3463 break;
3464 case IPA_IOC_QUERY_RT_TBL_INDEX32:
3465 cmd = IPA_IOC_QUERY_RT_TBL_INDEX;
3466 break;
3467 case IPA_IOC_WRITE_QMAPID32:
3468 cmd = IPA_IOC_WRITE_QMAPID;
3469 break;
3470 case IPA_IOC_MDFY_FLT_RULE32:
3471 cmd = IPA_IOC_MDFY_FLT_RULE;
3472 break;
3473 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD32:
3474 cmd = IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD;
3475 break;
3476 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL32:
3477 cmd = IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL;
3478 break;
3479 case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED32:
3480 cmd = IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED;
3481 break;
3482 case IPA_IOC_MDFY_RT_RULE32:
3483 cmd = IPA_IOC_MDFY_RT_RULE;
3484 break;
3485 case IPA_IOC_COMMIT_HDR:
3486 case IPA_IOC_RESET_HDR:
3487 case IPA_IOC_COMMIT_RT:
3488 case IPA_IOC_RESET_RT:
3489 case IPA_IOC_COMMIT_FLT:
3490 case IPA_IOC_RESET_FLT:
3491 case IPA_IOC_DUMP:
3492 case IPA_IOC_PUT_RT_TBL:
3493 case IPA_IOC_PUT_HDR:
3494 case IPA_IOC_SET_FLT:
3495 case IPA_IOC_QUERY_EP_MAPPING:
3496 break;
3497 default:
3498 return -ENOIOCTLCMD;
3499 }
3500 return ipa3_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
3501}
3502#endif
3503
3504static ssize_t ipa3_write(struct file *file, const char __user *buf,
3505 size_t count, loff_t *ppos);
3506
3507static const struct file_operations ipa3_drv_fops = {
3508 .owner = THIS_MODULE,
3509 .open = ipa3_open,
3510 .read = ipa3_read,
3511 .write = ipa3_write,
3512 .unlocked_ioctl = ipa3_ioctl,
3513#ifdef CONFIG_COMPAT
3514 .compat_ioctl = compat_ipa3_ioctl,
3515#endif
3516};
3517
3518static int ipa3_get_clks(struct device *dev)
3519{
Ghanim Fodi6a831342017-03-07 18:19:15 +02003520 if (ipa3_res.use_bw_vote) {
3521 IPADBG("Vote IPA clock by bw voting via bus scaling driver\n");
3522 ipa3_clk = NULL;
3523 return 0;
3524 }
3525
Amir Levy9659e592016-10-27 18:08:27 +03003526 ipa3_clk = clk_get(dev, "core_clk");
3527 if (IS_ERR(ipa3_clk)) {
3528 if (ipa3_clk != ERR_PTR(-EPROBE_DEFER))
3529 IPAERR("fail to get ipa clk\n");
3530 return PTR_ERR(ipa3_clk);
3531 }
3532 return 0;
3533}
3534
3535/**
3536 * _ipa_enable_clks_v3_0() - Enable IPA clocks.
3537 */
3538void _ipa_enable_clks_v3_0(void)
3539{
Ghanim Fodi6a831342017-03-07 18:19:15 +02003540 IPADBG_LOW("curr_ipa_clk_rate=%d", ipa3_ctx->curr_ipa_clk_rate);
Amir Levy9659e592016-10-27 18:08:27 +03003541 if (ipa3_clk) {
Ghanim Fodi6a831342017-03-07 18:19:15 +02003542 IPADBG_LOW("enabling gcc_ipa_clk\n");
Amir Levy9659e592016-10-27 18:08:27 +03003543 clk_prepare(ipa3_clk);
3544 clk_enable(ipa3_clk);
Amir Levy9659e592016-10-27 18:08:27 +03003545 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
Amir Levy9659e592016-10-27 18:08:27 +03003546 }
3547
Ghanim Fodi6a831342017-03-07 18:19:15 +02003548 ipa3_uc_notify_clk_state(true);
Amir Levy9659e592016-10-27 18:08:27 +03003549}
3550
3551static unsigned int ipa3_get_bus_vote(void)
3552{
3553 unsigned int idx = 1;
3554
Skylar Chang448d8b82017-08-08 17:30:32 -07003555 if (ipa3_ctx->curr_ipa_clk_rate == ipa3_ctx->ctrl->ipa_clk_rate_svs2) {
Amir Levy9659e592016-10-27 18:08:27 +03003556 idx = 1;
3557 } else if (ipa3_ctx->curr_ipa_clk_rate ==
Skylar Chang448d8b82017-08-08 17:30:32 -07003558 ipa3_ctx->ctrl->ipa_clk_rate_svs) {
3559 idx = 2;
3560 } else if (ipa3_ctx->curr_ipa_clk_rate ==
3561 ipa3_ctx->ctrl->ipa_clk_rate_nominal) {
3562 idx = 3;
Amir Levy9659e592016-10-27 18:08:27 +03003563 } else if (ipa3_ctx->curr_ipa_clk_rate ==
3564 ipa3_ctx->ctrl->ipa_clk_rate_turbo) {
3565 idx = ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases - 1;
3566 } else {
3567 WARN_ON(1);
3568 }
Michael Adisumartad8c88e52018-01-05 10:22:38 -08003569 IPADBG_LOW("curr %d idx %d\n", ipa3_ctx->curr_ipa_clk_rate, idx);
Amir Levy9659e592016-10-27 18:08:27 +03003570
3571 return idx;
3572}
3573
3574/**
Skylar Chang68c37d82018-04-07 16:42:36 -07003575 * ipa3_enable_clks() - Turn on IPA clocks
3576 *
3577 * Return codes:
3578 * None
3579 */
Amir Levy9659e592016-10-27 18:08:27 +03003580void ipa3_enable_clks(void)
3581{
Skylar Changefc0a0f2018-03-29 11:17:40 -07003582 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
3583 IPAERR("not supported in this mode\n");
3584 return;
3585 }
3586
Amir Levy9659e592016-10-27 18:08:27 +03003587 IPADBG("enabling IPA clocks and bus voting\n");
3588
Ghanim Fodi6a831342017-03-07 18:19:15 +02003589 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
3590 ipa3_get_bus_vote()))
3591 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03003592
Ghanim Fodi6a831342017-03-07 18:19:15 +02003593 ipa3_ctx->ctrl->ipa3_enable_clks();
Amir Levy9659e592016-10-27 18:08:27 +03003594}
3595
3596
3597/**
3598 * _ipa_disable_clks_v3_0() - Disable IPA clocks.
3599 */
3600void _ipa_disable_clks_v3_0(void)
3601{
Amir Levy9659e592016-10-27 18:08:27 +03003602 ipa3_suspend_apps_pipes(true);
3603 ipa3_uc_notify_clk_state(false);
Ghanim Fodi6a831342017-03-07 18:19:15 +02003604 if (ipa3_clk) {
3605 IPADBG_LOW("disabling gcc_ipa_clk\n");
Amir Levy9659e592016-10-27 18:08:27 +03003606 clk_disable_unprepare(ipa3_clk);
Ghanim Fodi6a831342017-03-07 18:19:15 +02003607 }
Amir Levy9659e592016-10-27 18:08:27 +03003608}
3609
3610/**
Skylar Chang68c37d82018-04-07 16:42:36 -07003611 * ipa3_disable_clks() - Turn off IPA clocks
3612 *
3613 * Return codes:
3614 * None
3615 */
Amir Levy9659e592016-10-27 18:08:27 +03003616void ipa3_disable_clks(void)
3617{
Skylar Changefc0a0f2018-03-29 11:17:40 -07003618 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
3619 IPAERR("not supported in this mode\n");
3620 return;
3621 }
3622
Amir Levy9659e592016-10-27 18:08:27 +03003623 IPADBG("disabling IPA clocks and bus voting\n");
3624
3625 ipa3_ctx->ctrl->ipa3_disable_clks();
3626
Ghanim Fodi6a831342017-03-07 18:19:15 +02003627 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl, 0))
3628 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03003629}
3630
3631/**
3632 * ipa3_start_tag_process() - Send TAG packet and wait for it to come back
3633 *
3634 * This function is called prior to clock gating when active client counter
3635 * is 1. TAG process ensures that there are no packets inside IPA HW that
Amir Levya59ed3f2017-03-05 17:30:55 +02003636 * were not submitted to the IPA client via the transport. During TAG process
3637 * all aggregation frames are (force) closed.
Amir Levy9659e592016-10-27 18:08:27 +03003638 *
3639 * Return codes:
3640 * None
3641 */
3642static void ipa3_start_tag_process(struct work_struct *work)
3643{
3644 int res;
3645
3646 IPADBG("starting TAG process\n");
3647 /* close aggregation frames on all pipes */
3648 res = ipa3_tag_aggr_force_close(-1);
3649 if (res)
3650 IPAERR("ipa3_tag_aggr_force_close failed %d\n", res);
3651 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("TAG_PROCESS");
3652
3653 IPADBG("TAG process done\n");
3654}
3655
3656/**
Skylar Chang68c37d82018-04-07 16:42:36 -07003657 * ipa3_active_clients_log_mod() - Log a modification in the active clients
3658 * reference count
3659 *
3660 * This method logs any modification in the active clients reference count:
3661 * It logs the modification in the circular history buffer
3662 * It logs the modification in the hash table - looking for an entry,
3663 * creating one if needed and deleting one if needed.
3664 *
3665 * @id: ipa3_active client logging info struct to hold the log information
3666 * @inc: a boolean variable to indicate whether the modification is an increase
3667 * or decrease
3668 * @int_ctx: a boolean variable to indicate whether this call is being made from
3669 * an interrupt context and therefore should allocate GFP_ATOMIC memory
3670 *
3671 * Method process:
3672 * - Hash the unique identifier string
3673 * - Find the hash in the table
3674 * 1)If found, increase or decrease the reference count
3675 * 2)If not found, allocate a new hash table entry struct and initialize it
3676 * - Remove and deallocate unneeded data structure
3677 * - Log the call in the circular history buffer (unless it is a simple call)
3678 */
Amir Levy9659e592016-10-27 18:08:27 +03003679void ipa3_active_clients_log_mod(struct ipa_active_client_logging_info *id,
3680 bool inc, bool int_ctx)
3681{
3682 char temp_str[IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN];
3683 unsigned long long t;
3684 unsigned long nanosec_rem;
3685 struct ipa3_active_client_htable_entry *hentry;
3686 struct ipa3_active_client_htable_entry *hfound;
3687 u32 hkey;
3688 char str_to_hash[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
Skylar Chang69ae50e2017-07-31 13:13:29 -07003689 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +03003690
Skylar Chang69ae50e2017-07-31 13:13:29 -07003691 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
3692 int_ctx = true;
Amir Levy9659e592016-10-27 18:08:27 +03003693 hfound = NULL;
3694 memset(str_to_hash, 0, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
3695 strlcpy(str_to_hash, id->id_string, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
Amir Levyd9f51132016-11-14 16:55:35 +02003696 hkey = jhash(str_to_hash, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN,
Amir Levy9659e592016-10-27 18:08:27 +03003697 0);
3698 hash_for_each_possible(ipa3_ctx->ipa3_active_clients_logging.htable,
3699 hentry, list, hkey) {
3700 if (!strcmp(hentry->id_string, id->id_string)) {
3701 hentry->count = hentry->count + (inc ? 1 : -1);
3702 hfound = hentry;
3703 }
3704 }
3705 if (hfound == NULL) {
3706 hentry = NULL;
3707 hentry = kzalloc(sizeof(
3708 struct ipa3_active_client_htable_entry),
3709 int_ctx ? GFP_ATOMIC : GFP_KERNEL);
3710 if (hentry == NULL) {
3711 IPAERR("failed allocating active clients hash entry");
Skylar Chang69ae50e2017-07-31 13:13:29 -07003712 spin_unlock_irqrestore(
3713 &ipa3_ctx->ipa3_active_clients_logging.lock,
3714 flags);
Amir Levy9659e592016-10-27 18:08:27 +03003715 return;
3716 }
3717 hentry->type = id->type;
3718 strlcpy(hentry->id_string, id->id_string,
3719 IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
3720 INIT_HLIST_NODE(&hentry->list);
3721 hentry->count = inc ? 1 : -1;
3722 hash_add(ipa3_ctx->ipa3_active_clients_logging.htable,
3723 &hentry->list, hkey);
3724 } else if (hfound->count == 0) {
3725 hash_del(&hfound->list);
3726 kfree(hfound);
3727 }
3728
3729 if (id->type != SIMPLE) {
3730 t = local_clock();
3731 nanosec_rem = do_div(t, 1000000000) / 1000;
3732 snprintf(temp_str, IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN,
3733 inc ? "[%5lu.%06lu] ^ %s, %s: %d" :
3734 "[%5lu.%06lu] v %s, %s: %d",
3735 (unsigned long)t, nanosec_rem,
3736 id->id_string, id->file, id->line);
3737 ipa3_active_clients_log_insert(temp_str);
3738 }
Skylar Chang69ae50e2017-07-31 13:13:29 -07003739 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
3740 flags);
Amir Levy9659e592016-10-27 18:08:27 +03003741}
3742
3743void ipa3_active_clients_log_dec(struct ipa_active_client_logging_info *id,
3744 bool int_ctx)
3745{
3746 ipa3_active_clients_log_mod(id, false, int_ctx);
3747}
3748
3749void ipa3_active_clients_log_inc(struct ipa_active_client_logging_info *id,
3750 bool int_ctx)
3751{
3752 ipa3_active_clients_log_mod(id, true, int_ctx);
3753}
3754
3755/**
Skylar Chang68c37d82018-04-07 16:42:36 -07003756 * ipa3_inc_client_enable_clks() - Increase active clients counter, and
3757 * enable ipa clocks if necessary
3758 *
3759 * Return codes:
3760 * None
3761 */
Amir Levy9659e592016-10-27 18:08:27 +03003762void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id)
3763{
Skylar Chang242952b2017-07-20 15:04:05 -07003764 int ret;
3765
Amir Levy9659e592016-10-27 18:08:27 +03003766 ipa3_active_clients_log_inc(id, false);
Skylar Chang242952b2017-07-20 15:04:05 -07003767 ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
3768 if (ret) {
3769 IPADBG_LOW("active clients = %d\n",
3770 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3771 return;
3772 }
3773
3774 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
3775
3776 /* somebody might voted to clocks meanwhile */
3777 ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
3778 if (ret) {
3779 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
3780 IPADBG_LOW("active clients = %d\n",
3781 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3782 return;
3783 }
3784
3785 ipa3_enable_clks();
3786 atomic_inc(&ipa3_ctx->ipa3_active_clients.cnt);
3787 IPADBG_LOW("active clients = %d\n",
3788 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3789 ipa3_suspend_apps_pipes(false);
3790 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03003791}
3792
3793/**
Skylar Chang68c37d82018-04-07 16:42:36 -07003794 * ipa3_inc_client_enable_clks_no_block() - Only increment the number of active
3795 * clients if no asynchronous actions should be done. Asynchronous actions are
3796 * locking a mutex and waking up IPA HW.
3797 *
3798 * Return codes: 0 for success
3799 * -EPERM if an asynchronous action should have been done
3800 */
Amir Levy9659e592016-10-27 18:08:27 +03003801int ipa3_inc_client_enable_clks_no_block(struct ipa_active_client_logging_info
3802 *id)
3803{
Skylar Chang242952b2017-07-20 15:04:05 -07003804 int ret;
Amir Levy9659e592016-10-27 18:08:27 +03003805
Skylar Chang242952b2017-07-20 15:04:05 -07003806 ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
3807 if (ret) {
3808 ipa3_active_clients_log_inc(id, true);
3809 IPADBG_LOW("active clients = %d\n",
3810 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3811 return 0;
Amir Levy9659e592016-10-27 18:08:27 +03003812 }
Amir Levy9659e592016-10-27 18:08:27 +03003813
Skylar Chang242952b2017-07-20 15:04:05 -07003814 return -EPERM;
3815}
3816
3817static void __ipa3_dec_client_disable_clks(void)
3818{
3819 int ret;
3820
3821 if (!atomic_read(&ipa3_ctx->ipa3_active_clients.cnt)) {
3822 IPAERR("trying to disable clocks with refcnt is 0!\n");
3823 ipa_assert();
3824 return;
3825 }
3826
3827 ret = atomic_add_unless(&ipa3_ctx->ipa3_active_clients.cnt, -1, 1);
3828 if (ret)
3829 goto bail;
3830
3831 /* seems like this is the only client holding the clocks */
3832 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
3833 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) == 1 &&
3834 ipa3_ctx->tag_process_before_gating) {
3835 ipa3_ctx->tag_process_before_gating = false;
3836 /*
3837 * When TAG process ends, active clients will be
3838 * decreased
3839 */
3840 queue_work(ipa3_ctx->power_mgmt_wq, &ipa3_tag_work);
3841 goto unlock_mutex;
3842 }
3843
3844 /* a different context might increase the clock reference meanwhile */
3845 ret = atomic_sub_return(1, &ipa3_ctx->ipa3_active_clients.cnt);
3846 if (ret > 0)
3847 goto unlock_mutex;
3848 ipa3_disable_clks();
3849
3850unlock_mutex:
3851 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
3852bail:
3853 IPADBG_LOW("active clients = %d\n",
3854 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
Amir Levy9659e592016-10-27 18:08:27 +03003855}
3856
3857/**
3858 * ipa3_dec_client_disable_clks() - Decrease active clients counter
3859 *
3860 * In case that there are no active clients this function also starts
3861 * TAG process. When TAG progress ends ipa clocks will be gated.
3862 * start_tag_process_again flag is set during this function to signal TAG
3863 * process to start again as there was another client that may send data to ipa
3864 *
3865 * Return codes:
3866 * None
3867 */
3868void ipa3_dec_client_disable_clks(struct ipa_active_client_logging_info *id)
3869{
Amir Levy9659e592016-10-27 18:08:27 +03003870 ipa3_active_clients_log_dec(id, false);
Skylar Chang242952b2017-07-20 15:04:05 -07003871 __ipa3_dec_client_disable_clks();
3872}
3873
3874static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work)
3875{
3876 __ipa3_dec_client_disable_clks();
3877}
3878
3879/**
3880 * ipa3_dec_client_disable_clks_no_block() - Decrease active clients counter
3881 * if possible without blocking. If this is the last client then the desrease
3882 * will happen from work queue context.
3883 *
3884 * Return codes:
3885 * None
3886 */
3887void ipa3_dec_client_disable_clks_no_block(
3888 struct ipa_active_client_logging_info *id)
3889{
3890 int ret;
3891
3892 ipa3_active_clients_log_dec(id, true);
3893 ret = atomic_add_unless(&ipa3_ctx->ipa3_active_clients.cnt, -1, 1);
3894 if (ret) {
3895 IPADBG_LOW("active clients = %d\n",
3896 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3897 return;
Amir Levy9659e592016-10-27 18:08:27 +03003898 }
Skylar Chang242952b2017-07-20 15:04:05 -07003899
3900 /* seems like this is the only client holding the clocks */
3901 queue_work(ipa3_ctx->power_mgmt_wq,
3902 &ipa_dec_clients_disable_clks_on_wq_work);
Amir Levy9659e592016-10-27 18:08:27 +03003903}
3904
3905/**
Skylar Chang68c37d82018-04-07 16:42:36 -07003906 * ipa3_inc_acquire_wakelock() - Increase active clients counter, and
3907 * acquire wakelock if necessary
3908 *
3909 * Return codes:
3910 * None
3911 */
Amir Levy9659e592016-10-27 18:08:27 +03003912void ipa3_inc_acquire_wakelock(void)
3913{
3914 unsigned long flags;
3915
3916 spin_lock_irqsave(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
3917 ipa3_ctx->wakelock_ref_cnt.cnt++;
3918 if (ipa3_ctx->wakelock_ref_cnt.cnt == 1)
3919 __pm_stay_awake(&ipa3_ctx->w_lock);
3920 IPADBG_LOW("active wakelock ref cnt = %d\n",
3921 ipa3_ctx->wakelock_ref_cnt.cnt);
3922 spin_unlock_irqrestore(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
3923}
3924
3925/**
3926 * ipa3_dec_release_wakelock() - Decrease active clients counter
3927 *
3928 * In case if the ref count is 0, release the wakelock.
3929 *
3930 * Return codes:
3931 * None
3932 */
3933void ipa3_dec_release_wakelock(void)
3934{
3935 unsigned long flags;
3936
3937 spin_lock_irqsave(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
3938 ipa3_ctx->wakelock_ref_cnt.cnt--;
3939 IPADBG_LOW("active wakelock ref cnt = %d\n",
3940 ipa3_ctx->wakelock_ref_cnt.cnt);
3941 if (ipa3_ctx->wakelock_ref_cnt.cnt == 0)
3942 __pm_relax(&ipa3_ctx->w_lock);
3943 spin_unlock_irqrestore(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
3944}
3945
Michael Adisumartac06df412017-09-19 10:10:35 -07003946int ipa3_set_clock_plan_from_pm(int idx)
3947{
3948 u32 clk_rate;
3949
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08003950 if (!ipa3_ctx->enable_clock_scaling)
3951 return 0;
3952
Skylar Changefc0a0f2018-03-29 11:17:40 -07003953 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
3954 IPAERR("not supported in this mode\n");
3955 return 0;
3956 }
3957
Michael Adisumartac06df412017-09-19 10:10:35 -07003958 IPADBG_LOW("idx = %d\n", idx);
3959
3960 if (idx <= 0 || idx >= ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases) {
3961 IPAERR("bad voltage\n");
3962 return -EINVAL;
3963 }
3964
3965 if (idx == 1)
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08003966 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs2;
Michael Adisumartac06df412017-09-19 10:10:35 -07003967 else if (idx == 2)
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08003968 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
Michael Adisumartac06df412017-09-19 10:10:35 -07003969 else if (idx == 3)
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08003970 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
3971 else if (idx == 4)
Michael Adisumartac06df412017-09-19 10:10:35 -07003972 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
3973 else {
3974 IPAERR("bad voltage\n");
3975 WARN_ON(1);
3976 return -EFAULT;
3977 }
3978
3979 if (clk_rate == ipa3_ctx->curr_ipa_clk_rate) {
3980 IPADBG_LOW("Same voltage\n");
3981 return 0;
3982 }
3983
3984 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
3985 ipa3_ctx->curr_ipa_clk_rate = clk_rate;
3986 ipa3_ctx->ipa3_active_clients.bus_vote_idx = idx;
3987 IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
3988 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) > 0) {
3989 if (ipa3_clk)
3990 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
3991 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
3992 ipa3_get_bus_vote()))
3993 WARN_ON(1);
3994 } else {
3995 IPADBG_LOW("clocks are gated, not setting rate\n");
3996 }
3997 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
3998 IPADBG_LOW("Done\n");
3999
4000 return 0;
4001}
4002
Amir Levy9659e592016-10-27 18:08:27 +03004003int ipa3_set_required_perf_profile(enum ipa_voltage_level floor_voltage,
4004 u32 bandwidth_mbps)
4005{
4006 enum ipa_voltage_level needed_voltage;
4007 u32 clk_rate;
4008
Skylar Changefc0a0f2018-03-29 11:17:40 -07004009 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
4010 IPAERR("not supported in this mode\n");
4011 return 0;
4012 }
4013
Amir Levy9659e592016-10-27 18:08:27 +03004014 IPADBG_LOW("floor_voltage=%d, bandwidth_mbps=%u",
4015 floor_voltage, bandwidth_mbps);
4016
4017 if (floor_voltage < IPA_VOLTAGE_UNSPECIFIED ||
4018 floor_voltage >= IPA_VOLTAGE_MAX) {
4019 IPAERR("bad voltage\n");
4020 return -EINVAL;
4021 }
4022
4023 if (ipa3_ctx->enable_clock_scaling) {
4024 IPADBG_LOW("Clock scaling is enabled\n");
4025 if (bandwidth_mbps >=
4026 ipa3_ctx->ctrl->clock_scaling_bw_threshold_turbo)
4027 needed_voltage = IPA_VOLTAGE_TURBO;
4028 else if (bandwidth_mbps >=
4029 ipa3_ctx->ctrl->clock_scaling_bw_threshold_nominal)
4030 needed_voltage = IPA_VOLTAGE_NOMINAL;
Skylar Chang448d8b82017-08-08 17:30:32 -07004031 else if (bandwidth_mbps >=
4032 ipa3_ctx->ctrl->clock_scaling_bw_threshold_svs)
Amir Levy9659e592016-10-27 18:08:27 +03004033 needed_voltage = IPA_VOLTAGE_SVS;
Skylar Chang448d8b82017-08-08 17:30:32 -07004034 else
4035 needed_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +03004036 } else {
4037 IPADBG_LOW("Clock scaling is disabled\n");
4038 needed_voltage = IPA_VOLTAGE_NOMINAL;
4039 }
4040
4041 needed_voltage = max(needed_voltage, floor_voltage);
4042 switch (needed_voltage) {
Skylar Chang448d8b82017-08-08 17:30:32 -07004043 case IPA_VOLTAGE_SVS2:
4044 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs2;
4045 break;
Amir Levy9659e592016-10-27 18:08:27 +03004046 case IPA_VOLTAGE_SVS:
4047 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
4048 break;
4049 case IPA_VOLTAGE_NOMINAL:
4050 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
4051 break;
4052 case IPA_VOLTAGE_TURBO:
4053 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
4054 break;
4055 default:
4056 IPAERR("bad voltage\n");
4057 WARN_ON(1);
4058 return -EFAULT;
4059 }
4060
4061 if (clk_rate == ipa3_ctx->curr_ipa_clk_rate) {
4062 IPADBG_LOW("Same voltage\n");
4063 return 0;
4064 }
4065
Skylar Chang242952b2017-07-20 15:04:05 -07004066 /* Hold the mutex to avoid race conditions with ipa3_enable_clocks() */
4067 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004068 ipa3_ctx->curr_ipa_clk_rate = clk_rate;
4069 IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
Skylar Chang242952b2017-07-20 15:04:05 -07004070 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) > 0) {
Ghanim Fodi6a831342017-03-07 18:19:15 +02004071 if (ipa3_clk)
4072 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
4073 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
Skylar Chang242952b2017-07-20 15:04:05 -07004074 ipa3_get_bus_vote()))
Ghanim Fodi6a831342017-03-07 18:19:15 +02004075 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03004076 } else {
4077 IPADBG_LOW("clocks are gated, not setting rate\n");
4078 }
Skylar Chang242952b2017-07-20 15:04:05 -07004079 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004080 IPADBG_LOW("Done\n");
Skylar Chang1cbe99c2017-05-01 13:44:03 -07004081
Amir Levy9659e592016-10-27 18:08:27 +03004082 return 0;
4083}
4084
Amir Levya59ed3f2017-03-05 17:30:55 +02004085static void ipa3_process_irq_schedule_rel(void)
Amir Levy9659e592016-10-27 18:08:27 +03004086{
4087 queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
Amir Levya59ed3f2017-03-05 17:30:55 +02004088 &ipa3_transport_release_resource_work,
Amir Levy9659e592016-10-27 18:08:27 +03004089 msecs_to_jiffies(IPA_TRANSPORT_PROD_TIMEOUT_MSEC));
4090}
4091
4092/**
Skylar Chang68c37d82018-04-07 16:42:36 -07004093 * ipa3_suspend_handler() - Handles the suspend interrupt:
4094 * wakes up the suspended peripheral by requesting its consumer
4095 * @interrupt: Interrupt type
4096 * @private_data: The client's private data
4097 * @interrupt_data: Interrupt specific information data
4098 */
Amir Levy9659e592016-10-27 18:08:27 +03004099void ipa3_suspend_handler(enum ipa_irq_type interrupt,
4100 void *private_data,
4101 void *interrupt_data)
4102{
4103 enum ipa_rm_resource_name resource;
4104 u32 suspend_data =
4105 ((struct ipa_tx_suspend_irq_data *)interrupt_data)->endpoints;
4106 u32 bmsk = 1;
4107 u32 i = 0;
4108 int res;
4109 struct ipa_ep_cfg_holb holb_cfg;
Michael Adisumarta3e350812017-09-18 14:54:36 -07004110 u32 pipe_bitmask = 0;
Amir Levy9659e592016-10-27 18:08:27 +03004111
4112 IPADBG("interrupt=%d, interrupt_data=%u\n",
4113 interrupt, suspend_data);
4114 memset(&holb_cfg, 0, sizeof(holb_cfg));
4115 holb_cfg.tmr_val = 0;
4116
Michael Adisumarta3e350812017-09-18 14:54:36 -07004117 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++, bmsk = bmsk << 1) {
Amir Levy9659e592016-10-27 18:08:27 +03004118 if ((suspend_data & bmsk) && (ipa3_ctx->ep[i].valid)) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07004119 if (ipa3_ctx->use_ipa_pm) {
4120 pipe_bitmask |= bmsk;
4121 continue;
4122 }
Amir Levy9659e592016-10-27 18:08:27 +03004123 if (IPA_CLIENT_IS_APPS_CONS(ipa3_ctx->ep[i].client)) {
4124 /*
4125 * pipe will be unsuspended as part of
4126 * enabling IPA clocks
4127 */
Skylar Chang0d06bb12017-02-24 11:22:03 -08004128 mutex_lock(&ipa3_ctx->transport_pm.
4129 transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004130 if (!atomic_read(
4131 &ipa3_ctx->transport_pm.dec_clients)
4132 ) {
4133 IPA_ACTIVE_CLIENTS_INC_EP(
4134 ipa3_ctx->ep[i].client);
4135 IPADBG_LOW("Pipes un-suspended.\n");
4136 IPADBG_LOW("Enter poll mode.\n");
4137 atomic_set(
4138 &ipa3_ctx->transport_pm.dec_clients,
4139 1);
Skylar Chang9e3b6492017-11-07 09:49:48 -08004140 /*
4141 * acquire wake lock as long as suspend
4142 * vote is held
4143 */
4144 ipa3_inc_acquire_wakelock();
Amir Levya59ed3f2017-03-05 17:30:55 +02004145 ipa3_process_irq_schedule_rel();
Amir Levy9659e592016-10-27 18:08:27 +03004146 }
Skylar Chang0d06bb12017-02-24 11:22:03 -08004147 mutex_unlock(&ipa3_ctx->transport_pm.
4148 transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004149 } else {
4150 resource = ipa3_get_rm_resource_from_ep(i);
4151 res =
4152 ipa_rm_request_resource_with_timer(resource);
4153 if (res == -EPERM &&
4154 IPA_CLIENT_IS_CONS(
4155 ipa3_ctx->ep[i].client)) {
4156 holb_cfg.en = 1;
4157 res = ipa3_cfg_ep_holb_by_client(
4158 ipa3_ctx->ep[i].client, &holb_cfg);
4159 if (res) {
4160 IPAERR("holb en fail, stall\n");
4161 BUG();
4162 }
4163 }
4164 }
4165 }
Michael Adisumarta3e350812017-09-18 14:54:36 -07004166 }
4167 if (ipa3_ctx->use_ipa_pm) {
4168 res = ipa_pm_handle_suspend(pipe_bitmask);
4169 if (res) {
4170 IPAERR("ipa_pm_handle_suspend failed %d\n", res);
4171 return;
4172 }
Amir Levy9659e592016-10-27 18:08:27 +03004173 }
4174}
4175
4176/**
Skylar Chang68c37d82018-04-07 16:42:36 -07004177 * ipa3_restore_suspend_handler() - restores the original suspend IRQ handler
4178 * as it was registered in the IPA init sequence.
4179 * Return codes:
4180 * 0: success
4181 * -EPERM: failed to remove current handler or failed to add original handler
4182 */
Amir Levy9659e592016-10-27 18:08:27 +03004183int ipa3_restore_suspend_handler(void)
4184{
4185 int result = 0;
4186
4187 result = ipa3_remove_interrupt_handler(IPA_TX_SUSPEND_IRQ);
4188 if (result) {
4189 IPAERR("remove handler for suspend interrupt failed\n");
4190 return -EPERM;
4191 }
4192
4193 result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
4194 ipa3_suspend_handler, false, NULL);
4195 if (result) {
4196 IPAERR("register handler for suspend interrupt failed\n");
4197 result = -EPERM;
4198 }
4199
4200 IPADBG("suspend handler successfully restored\n");
4201
4202 return result;
4203}
4204
4205static int ipa3_apps_cons_release_resource(void)
4206{
4207 return 0;
4208}
4209
4210static int ipa3_apps_cons_request_resource(void)
4211{
4212 return 0;
4213}
4214
Amir Levya59ed3f2017-03-05 17:30:55 +02004215static void ipa3_transport_release_resource(struct work_struct *work)
Amir Levy9659e592016-10-27 18:08:27 +03004216{
Sridhar Ancha99b505b2016-04-21 23:11:10 +05304217 mutex_lock(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004218 /* check whether still need to decrease client usage */
4219 if (atomic_read(&ipa3_ctx->transport_pm.dec_clients)) {
4220 if (atomic_read(&ipa3_ctx->transport_pm.eot_activity)) {
4221 IPADBG("EOT pending Re-scheduling\n");
Amir Levya59ed3f2017-03-05 17:30:55 +02004222 ipa3_process_irq_schedule_rel();
Amir Levy9659e592016-10-27 18:08:27 +03004223 } else {
4224 atomic_set(&ipa3_ctx->transport_pm.dec_clients, 0);
Skylar Chang9e3b6492017-11-07 09:49:48 -08004225 ipa3_dec_release_wakelock();
Amir Levya59ed3f2017-03-05 17:30:55 +02004226 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("TRANSPORT_RESOURCE");
Amir Levy9659e592016-10-27 18:08:27 +03004227 }
4228 }
4229 atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
Sridhar Ancha99b505b2016-04-21 23:11:10 +05304230 mutex_unlock(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004231}
4232
4233int ipa3_create_apps_resource(void)
4234{
4235 struct ipa_rm_create_params apps_cons_create_params;
4236 struct ipa_rm_perf_profile profile;
4237 int result = 0;
4238
4239 memset(&apps_cons_create_params, 0,
4240 sizeof(apps_cons_create_params));
4241 apps_cons_create_params.name = IPA_RM_RESOURCE_APPS_CONS;
4242 apps_cons_create_params.request_resource =
4243 ipa3_apps_cons_request_resource;
4244 apps_cons_create_params.release_resource =
4245 ipa3_apps_cons_release_resource;
4246 result = ipa_rm_create_resource(&apps_cons_create_params);
4247 if (result) {
4248 IPAERR("ipa_rm_create_resource failed\n");
4249 return result;
4250 }
4251
4252 profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
4253 ipa_rm_set_perf_profile(IPA_RM_RESOURCE_APPS_CONS, &profile);
4254
4255 return result;
4256}
4257
4258/**
4259 * ipa3_init_interrupts() - Register to IPA IRQs
4260 *
4261 * Return codes: 0 in success, negative in failure
4262 *
4263 */
4264int ipa3_init_interrupts(void)
4265{
4266 int result;
4267
4268 /*register IPA IRQ handler*/
4269 result = ipa3_interrupts_init(ipa3_res.ipa_irq, 0,
Skylar Changefc0a0f2018-03-29 11:17:40 -07004270 &ipa3_ctx->master_pdev->dev);
Amir Levy9659e592016-10-27 18:08:27 +03004271 if (result) {
4272 IPAERR("ipa interrupts initialization failed\n");
4273 return -ENODEV;
4274 }
4275
4276 /*add handler for suspend interrupt*/
4277 result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
4278 ipa3_suspend_handler, false, NULL);
4279 if (result) {
4280 IPAERR("register handler for suspend interrupt failed\n");
4281 result = -ENODEV;
4282 goto fail_add_interrupt_handler;
4283 }
4284
4285 return 0;
4286
4287fail_add_interrupt_handler:
Skylar Changefc0a0f2018-03-29 11:17:40 -07004288 free_irq(ipa3_res.ipa_irq, &ipa3_ctx->master_pdev->dev);
Amir Levy9659e592016-10-27 18:08:27 +03004289 return result;
4290}
4291
4292/**
4293 * ipa3_destroy_flt_tbl_idrs() - destroy the idr structure for flt tables
4294 * The idr strcuture per filtering table is intended for rule id generation
4295 * per filtering rule.
4296 */
4297static void ipa3_destroy_flt_tbl_idrs(void)
4298{
4299 int i;
4300 struct ipa3_flt_tbl *flt_tbl;
4301
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004302 idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
4303 idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
4304
Amir Levy9659e592016-10-27 18:08:27 +03004305 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4306 if (!ipa_is_ep_support_flt(i))
4307 continue;
4308
4309 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004310 flt_tbl->rule_ids = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004311 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004312 flt_tbl->rule_ids = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004313 }
4314}
4315
4316static void ipa3_freeze_clock_vote_and_notify_modem(void)
4317{
4318 int res;
Amir Levy9659e592016-10-27 18:08:27 +03004319 struct ipa_active_client_logging_info log_info;
4320
4321 if (ipa3_ctx->smp2p_info.res_sent)
4322 return;
4323
Skylar Change1209942017-02-02 14:26:38 -08004324 if (ipa3_ctx->smp2p_info.out_base_id == 0) {
4325 IPAERR("smp2p out gpio not assigned\n");
4326 return;
4327 }
4328
Amir Levy9659e592016-10-27 18:08:27 +03004329 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "FREEZE_VOTE");
4330 res = ipa3_inc_client_enable_clks_no_block(&log_info);
4331 if (res)
Skylar Change1209942017-02-02 14:26:38 -08004332 ipa3_ctx->smp2p_info.ipa_clk_on = false;
Amir Levy9659e592016-10-27 18:08:27 +03004333 else
Skylar Change1209942017-02-02 14:26:38 -08004334 ipa3_ctx->smp2p_info.ipa_clk_on = true;
Amir Levy9659e592016-10-27 18:08:27 +03004335
Skylar Change1209942017-02-02 14:26:38 -08004336 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4337 IPA_GPIO_OUT_CLK_VOTE_IDX,
4338 ipa3_ctx->smp2p_info.ipa_clk_on);
4339 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4340 IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 1);
Amir Levy9659e592016-10-27 18:08:27 +03004341
Skylar Change1209942017-02-02 14:26:38 -08004342 ipa3_ctx->smp2p_info.res_sent = true;
4343 IPADBG("IPA clocks are %s\n",
4344 ipa3_ctx->smp2p_info.ipa_clk_on ? "ON" : "OFF");
4345}
4346
4347void ipa3_reset_freeze_vote(void)
4348{
4349 if (ipa3_ctx->smp2p_info.res_sent == false)
4350 return;
4351
4352 if (ipa3_ctx->smp2p_info.ipa_clk_on)
4353 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("FREEZE_VOTE");
4354
4355 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4356 IPA_GPIO_OUT_CLK_VOTE_IDX, 0);
4357 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4358 IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 0);
4359
4360 ipa3_ctx->smp2p_info.res_sent = false;
4361 ipa3_ctx->smp2p_info.ipa_clk_on = false;
Amir Levy9659e592016-10-27 18:08:27 +03004362}
4363
4364static int ipa3_panic_notifier(struct notifier_block *this,
4365 unsigned long event, void *ptr)
4366{
4367 int res;
4368
4369 ipa3_freeze_clock_vote_and_notify_modem();
4370
4371 IPADBG("Calling uC panic handler\n");
4372 res = ipa3_uc_panic_notifier(this, event, ptr);
4373 if (res)
4374 IPAERR("uC panic handler failed %d\n", res);
4375
Michael Adisumartaedba22d2018-04-19 12:28:33 -07004376 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) != 0)
4377 ipahal_print_all_regs();
4378
Amir Levy9659e592016-10-27 18:08:27 +03004379 return NOTIFY_DONE;
4380}
4381
4382static struct notifier_block ipa3_panic_blk = {
4383 .notifier_call = ipa3_panic_notifier,
4384 /* IPA panic handler needs to run before modem shuts down */
4385 .priority = INT_MAX,
4386};
4387
4388static void ipa3_register_panic_hdlr(void)
4389{
4390 atomic_notifier_chain_register(&panic_notifier_list,
4391 &ipa3_panic_blk);
4392}
4393
4394static void ipa3_trigger_ipa_ready_cbs(void)
4395{
4396 struct ipa3_ready_cb_info *info;
4397
4398 mutex_lock(&ipa3_ctx->lock);
4399
4400 /* Call all the CBs */
4401 list_for_each_entry(info, &ipa3_ctx->ipa_ready_cb_list, link)
4402 if (info->ready_cb)
4403 info->ready_cb(info->user_data);
4404
4405 mutex_unlock(&ipa3_ctx->lock);
4406}
4407
4408static int ipa3_gsi_pre_fw_load_init(void)
4409{
4410 int result;
4411
4412 result = gsi_configure_regs(ipa3_res.transport_mem_base,
4413 ipa3_res.transport_mem_size,
4414 ipa3_res.ipa_mem_base);
4415 if (result) {
4416 IPAERR("Failed to configure GSI registers\n");
4417 return -EINVAL;
4418 }
4419
4420 return 0;
4421}
4422
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004423static void ipa3_uc_is_loaded(void)
4424{
4425 IPADBG("\n");
4426 complete_all(&ipa3_ctx->uc_loaded_completion_obj);
4427}
4428
Amir Levy41644242016-11-03 15:38:09 +02004429static enum gsi_ver ipa3_get_gsi_ver(enum ipa_hw_type ipa_hw_type)
4430{
4431 enum gsi_ver gsi_ver;
4432
4433 switch (ipa_hw_type) {
4434 case IPA_HW_v3_0:
4435 case IPA_HW_v3_1:
4436 gsi_ver = GSI_VER_1_0;
4437 break;
4438 case IPA_HW_v3_5:
4439 gsi_ver = GSI_VER_1_2;
4440 break;
4441 case IPA_HW_v3_5_1:
4442 gsi_ver = GSI_VER_1_3;
4443 break;
Michael Adisumarta891a4ff2017-05-16 16:40:06 -07004444 case IPA_HW_v4_0:
4445 gsi_ver = GSI_VER_2_0;
4446 break;
Amir Levy41644242016-11-03 15:38:09 +02004447 default:
4448 IPAERR("No GSI version for ipa type %d\n", ipa_hw_type);
4449 WARN_ON(1);
4450 gsi_ver = GSI_VER_ERR;
4451 }
4452
4453 IPADBG("GSI version %d\n", gsi_ver);
4454
4455 return gsi_ver;
4456}
4457
Amir Levy9659e592016-10-27 18:08:27 +03004458/**
4459 * ipa3_post_init() - Initialize the IPA Driver (Part II).
4460 * This part contains all initialization which requires interaction with
Amir Levya59ed3f2017-03-05 17:30:55 +02004461 * IPA HW (via GSI).
Amir Levy9659e592016-10-27 18:08:27 +03004462 *
4463 * @resource_p: contain platform specific values from DST file
4464 * @pdev: The platform device structure representing the IPA driver
4465 *
4466 * Function initialization process:
Amir Levy54fe4d32017-03-16 11:21:49 +02004467 * - Initialize endpoints bitmaps
4468 * - Initialize resource groups min and max values
4469 * - Initialize filtering lists heads and idr
4470 * - Initialize interrupts
Amir Levya59ed3f2017-03-05 17:30:55 +02004471 * - Register GSI
Amir Levy9659e592016-10-27 18:08:27 +03004472 * - Setup APPS pipes
4473 * - Initialize tethering bridge
4474 * - Initialize IPA debugfs
4475 * - Initialize IPA uC interface
4476 * - Initialize WDI interface
4477 * - Initialize USB interface
4478 * - Register for panic handler
4479 * - Trigger IPA ready callbacks (to all subscribers)
4480 * - Trigger IPA completion object (to all who wait on it)
4481 */
4482static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p,
4483 struct device *ipa_dev)
4484{
4485 int result;
Amir Levy9659e592016-10-27 18:08:27 +03004486 struct gsi_per_props gsi_props;
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004487 struct ipa3_uc_hdlrs uc_hdlrs = { 0 };
Amir Levy54fe4d32017-03-16 11:21:49 +02004488 struct ipa3_flt_tbl *flt_tbl;
4489 int i;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004490 struct idr *idr;
Amir Levy54fe4d32017-03-16 11:21:49 +02004491
Utkarsh Saxenaded78142017-05-03 14:04:30 +05304492 if (ipa3_ctx == NULL) {
4493 IPADBG("IPA driver haven't initialized\n");
4494 return -ENXIO;
4495 }
4496
4497 /* Prevent consequent calls from trying to load the FW again. */
4498 if (ipa3_ctx->ipa_initialization_complete)
4499 return 0;
Mohammed Javidc6db3362018-02-13 13:41:38 +05304500
4501 IPADBG("active clients = %d\n",
4502 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
Skylar Chang40430532017-07-06 14:31:57 -07004503 /* move proxy vote for modem on ipa3_post_init */
Mohammed Javidc6db3362018-02-13 13:41:38 +05304504 if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0)
4505 ipa3_proxy_clk_vote();
Utkarsh Saxenaded78142017-05-03 14:04:30 +05304506
Skylar Changefc0a0f2018-03-29 11:17:40 -07004507 /* SMMU was already attached if used, safe to do allocations */
4508 if (ipahal_init(ipa3_ctx->ipa_hw_type, ipa3_ctx->mmio,
4509 ipa3_ctx->pdev)) {
4510 IPAERR("fail to init ipahal\n");
4511 result = -EFAULT;
4512 goto fail_ipahal;
4513 }
4514
4515 result = ipa3_init_hw();
4516 if (result) {
4517 IPAERR(":error initializing HW\n");
4518 result = -ENODEV;
4519 goto fail_init_hw;
4520 }
4521 IPADBG("IPA HW initialization sequence completed");
4522
4523 ipa3_ctx->ipa_num_pipes = ipa3_get_num_pipes();
4524 if (ipa3_ctx->ipa_num_pipes > IPA3_MAX_NUM_PIPES) {
4525 IPAERR("IPA has more pipes then supported has %d, max %d\n",
4526 ipa3_ctx->ipa_num_pipes, IPA3_MAX_NUM_PIPES);
4527 result = -ENODEV;
4528 goto fail_init_hw;
4529 }
4530
4531 ipa3_ctx->ctrl->ipa_sram_read_settings();
4532 IPADBG("SRAM, size: 0x%x, restricted bytes: 0x%x\n",
4533 ipa3_ctx->smem_sz, ipa3_ctx->smem_restricted_bytes);
4534
4535 IPADBG("hdr_lcl=%u ip4_rt_hash=%u ip4_rt_nonhash=%u\n",
4536 ipa3_ctx->hdr_tbl_lcl, ipa3_ctx->ip4_rt_tbl_hash_lcl,
4537 ipa3_ctx->ip4_rt_tbl_nhash_lcl);
4538
4539 IPADBG("ip6_rt_hash=%u ip6_rt_nonhash=%u\n",
4540 ipa3_ctx->ip6_rt_tbl_hash_lcl, ipa3_ctx->ip6_rt_tbl_nhash_lcl);
4541
4542 IPADBG("ip4_flt_hash=%u ip4_flt_nonhash=%u\n",
4543 ipa3_ctx->ip4_flt_tbl_hash_lcl,
4544 ipa3_ctx->ip4_flt_tbl_nhash_lcl);
4545
4546 IPADBG("ip6_flt_hash=%u ip6_flt_nonhash=%u\n",
4547 ipa3_ctx->ip6_flt_tbl_hash_lcl,
4548 ipa3_ctx->ip6_flt_tbl_nhash_lcl);
4549
4550 if (ipa3_ctx->smem_reqd_sz > ipa3_ctx->smem_sz) {
4551 IPAERR("SW expect more core memory, needed %d, avail %d\n",
4552 ipa3_ctx->smem_reqd_sz, ipa3_ctx->smem_sz);
4553 result = -ENOMEM;
4554 goto fail_init_hw;
4555 }
4556
4557 result = ipa3_allocate_dma_task_for_gsi();
4558 if (result) {
4559 IPAERR("failed to allocate dma task\n");
4560 goto fail_dma_task;
4561 }
4562
4563 if (ipa3_nat_ipv6ct_init_devices()) {
4564 IPAERR("unable to init NAT and IPv6CT devices\n");
4565 result = -ENODEV;
4566 goto fail_nat_ipv6ct_init_dev;
4567 }
4568
4569 result = ipa3_alloc_pkt_init();
4570 if (result) {
4571 IPAERR("Failed to alloc pkt_init payload\n");
4572 result = -ENODEV;
4573 goto fail_allok_pkt_init;
4574 }
4575
4576 if (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5)
4577 ipa3_enable_dcd();
4578
Amir Levy54fe4d32017-03-16 11:21:49 +02004579 /*
4580 * indication whether working in MHI config or non MHI config is given
4581 * in ipa3_write which is launched before ipa3_post_init. i.e. from
4582 * this point it is safe to use ipa3_ep_mapping array and the correct
4583 * entry will be returned from ipa3_get_hw_type_index()
4584 */
4585 ipa_init_ep_flt_bitmap();
4586 IPADBG("EP with flt support bitmap 0x%x (%u pipes)\n",
4587 ipa3_ctx->ep_flt_bitmap, ipa3_ctx->ep_flt_num);
4588
4589 /* Assign resource limitation to each group */
4590 ipa3_set_resorce_groups_min_max_limits();
4591
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004592 idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
4593 idr_init(idr);
4594 idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
4595 idr_init(idr);
4596
Amir Levy54fe4d32017-03-16 11:21:49 +02004597 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4598 if (!ipa_is_ep_support_flt(i))
4599 continue;
4600
4601 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
4602 INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
4603 flt_tbl->in_sys[IPA_RULE_HASHABLE] =
4604 !ipa3_ctx->ip4_flt_tbl_hash_lcl;
4605 flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
4606 !ipa3_ctx->ip4_flt_tbl_nhash_lcl;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004607 flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v4];
Amir Levy54fe4d32017-03-16 11:21:49 +02004608
4609 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
4610 INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
4611 flt_tbl->in_sys[IPA_RULE_HASHABLE] =
4612 !ipa3_ctx->ip6_flt_tbl_hash_lcl;
4613 flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
4614 !ipa3_ctx->ip6_flt_tbl_nhash_lcl;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004615 flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v6];
Amir Levy54fe4d32017-03-16 11:21:49 +02004616 }
4617
4618 if (!ipa3_ctx->apply_rg10_wa) {
4619 result = ipa3_init_interrupts();
4620 if (result) {
4621 IPAERR("ipa initialization of interrupts failed\n");
4622 result = -ENODEV;
4623 goto fail_register_device;
4624 }
4625 } else {
4626 IPADBG("Initialization of ipa interrupts skipped\n");
4627 }
Amir Levy9659e592016-10-27 18:08:27 +03004628
Amir Levy3afd94a2017-01-05 10:19:13 +02004629 /*
Amir Levy5cfbb322017-01-09 14:53:02 +02004630 * IPAv3.5 and above requires to disable prefetch for USB in order
Skylar Chang84099692018-04-24 14:43:03 -07004631 * to allow MBIM to work.
Amir Levy3afd94a2017-01-05 10:19:13 +02004632 */
Michael Adisumartad68ab112017-06-14 11:40:06 -07004633 if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5
4634 && ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) &&
Amir Levy5cfbb322017-01-09 14:53:02 +02004635 (!ipa3_ctx->ipa_config_is_mhi))
Amir Levy3afd94a2017-01-05 10:19:13 +02004636 ipa3_disable_prefetch(IPA_CLIENT_USB_CONS);
4637
Skylar Chang84099692018-04-24 14:43:03 -07004638 if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5
4639 && ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) &&
4640 (ipa3_ctx->ipa_config_is_mhi))
4641 ipa3_disable_prefetch(IPA_CLIENT_MHI_CONS);
4642
Amir Levya59ed3f2017-03-05 17:30:55 +02004643 memset(&gsi_props, 0, sizeof(gsi_props));
4644 gsi_props.ver = ipa3_get_gsi_ver(resource_p->ipa_hw_type);
4645 gsi_props.ee = resource_p->ee;
4646 gsi_props.intr = GSI_INTR_IRQ;
4647 gsi_props.irq = resource_p->transport_irq;
4648 gsi_props.phys_addr = resource_p->transport_mem_base;
4649 gsi_props.size = resource_p->transport_mem_size;
4650 gsi_props.notify_cb = ipa_gsi_notify_cb;
4651 gsi_props.req_clk_cb = NULL;
4652 gsi_props.rel_clk_cb = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004653
Ghanim Fodic823bc62017-10-21 17:29:53 +03004654 if (ipa3_ctx->ipa_config_is_mhi) {
4655 gsi_props.mhi_er_id_limits_valid = true;
4656 gsi_props.mhi_er_id_limits[0] = resource_p->mhi_evid_limits[0];
4657 gsi_props.mhi_er_id_limits[1] = resource_p->mhi_evid_limits[1];
4658 }
4659
Amir Levya59ed3f2017-03-05 17:30:55 +02004660 result = gsi_register_device(&gsi_props,
4661 &ipa3_ctx->gsi_dev_hdl);
4662 if (result != GSI_STATUS_SUCCESS) {
4663 IPAERR(":gsi register error - %d\n", result);
4664 result = -ENODEV;
4665 goto fail_register_device;
Amir Levy9659e592016-10-27 18:08:27 +03004666 }
Amir Levya59ed3f2017-03-05 17:30:55 +02004667 IPADBG("IPA gsi is registered\n");
Amir Levy9659e592016-10-27 18:08:27 +03004668
4669 /* setup the AP-IPA pipes */
4670 if (ipa3_setup_apps_pipes()) {
4671 IPAERR(":failed to setup IPA-Apps pipes\n");
4672 result = -ENODEV;
4673 goto fail_setup_apps_pipes;
4674 }
Amir Levya59ed3f2017-03-05 17:30:55 +02004675 IPADBG("IPA GPI pipes were connected\n");
Amir Levy9659e592016-10-27 18:08:27 +03004676
4677 if (ipa3_ctx->use_ipa_teth_bridge) {
4678 /* Initialize the tethering bridge driver */
4679 result = ipa3_teth_bridge_driver_init();
4680 if (result) {
4681 IPAERR(":teth_bridge init failed (%d)\n", -result);
4682 result = -ENODEV;
4683 goto fail_teth_bridge_driver_init;
4684 }
4685 IPADBG("teth_bridge initialized");
4686 }
4687
Amir Levy9659e592016-10-27 18:08:27 +03004688 result = ipa3_uc_interface_init();
4689 if (result)
4690 IPAERR(":ipa Uc interface init failed (%d)\n", -result);
4691 else
4692 IPADBG(":ipa Uc interface init ok\n");
4693
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004694 uc_hdlrs.ipa_uc_loaded_hdlr = ipa3_uc_is_loaded;
4695 ipa3_uc_register_handlers(IPA_HW_FEATURE_COMMON, &uc_hdlrs);
4696
Amir Levy9659e592016-10-27 18:08:27 +03004697 result = ipa3_wdi_init();
4698 if (result)
4699 IPAERR(":wdi init failed (%d)\n", -result);
4700 else
4701 IPADBG(":wdi init ok\n");
4702
4703 result = ipa3_ntn_init();
4704 if (result)
4705 IPAERR(":ntn init failed (%d)\n", -result);
4706 else
4707 IPADBG(":ntn init ok\n");
4708
Skylar Chang6f6e3072017-07-28 10:03:47 -07004709 result = ipa_hw_stats_init();
4710 if (result)
4711 IPAERR("fail to init stats %d\n", result);
4712 else
4713 IPADBG(":stats init ok\n");
4714
Amir Levy9659e592016-10-27 18:08:27 +03004715 ipa3_register_panic_hdlr();
4716
Amir Levy9659e592016-10-27 18:08:27 +03004717 mutex_lock(&ipa3_ctx->lock);
4718 ipa3_ctx->ipa_initialization_complete = true;
4719 mutex_unlock(&ipa3_ctx->lock);
4720
4721 ipa3_trigger_ipa_ready_cbs();
4722 complete_all(&ipa3_ctx->init_completion_obj);
4723 pr_info("IPA driver initialization was successful.\n");
4724
Skylar Chang96140a92018-02-05 15:44:34 -08004725 ipa3_debugfs_init();
4726
Amir Levy9659e592016-10-27 18:08:27 +03004727 return 0;
4728
4729fail_teth_bridge_driver_init:
4730 ipa3_teardown_apps_pipes();
4731fail_setup_apps_pipes:
Amir Levya59ed3f2017-03-05 17:30:55 +02004732 gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03004733fail_register_device:
Amir Levy9659e592016-10-27 18:08:27 +03004734 ipa3_destroy_flt_tbl_idrs();
Mohammed Javidc6db3362018-02-13 13:41:38 +05304735 ipa3_proxy_clk_unvote();
Skylar Changefc0a0f2018-03-29 11:17:40 -07004736fail_allok_pkt_init:
4737 ipa3_nat_ipv6ct_destroy_devices();
4738fail_nat_ipv6ct_init_dev:
4739 ipa3_free_dma_task_for_gsi();
4740fail_dma_task:
4741fail_init_hw:
4742 ipahal_destroy();
4743fail_ipahal:
4744
Amir Levy9659e592016-10-27 18:08:27 +03004745 return result;
4746}
4747
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004748static int ipa3_manual_load_ipa_fws(void)
Amir Levy9659e592016-10-27 18:08:27 +03004749{
4750 int result;
4751 const struct firmware *fw;
4752
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004753 IPADBG("Manual FW loading process initiated\n");
Amir Levy9659e592016-10-27 18:08:27 +03004754
Skylar Changefc0a0f2018-03-29 11:17:40 -07004755 result = request_firmware(&fw, IPA_FWS_PATH, ipa3_ctx->cdev.dev);
Amir Levy9659e592016-10-27 18:08:27 +03004756 if (result < 0) {
4757 IPAERR("request_firmware failed, error %d\n", result);
4758 return result;
4759 }
4760 if (fw == NULL) {
4761 IPAERR("Firmware is NULL!\n");
4762 return -EINVAL;
4763 }
4764
4765 IPADBG("FWs are available for loading\n");
4766
Ghanim Fodi37b64952017-01-24 15:42:30 +02004767 result = ipa3_load_fws(fw, ipa3_res.transport_mem_base);
Amir Levy9659e592016-10-27 18:08:27 +03004768 if (result) {
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004769 IPAERR("Manual IPA FWs loading has failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03004770 release_firmware(fw);
4771 return result;
4772 }
4773
4774 result = gsi_enable_fw(ipa3_res.transport_mem_base,
Amir Levy85dcd172016-12-06 17:47:39 +02004775 ipa3_res.transport_mem_size,
4776 ipa3_get_gsi_ver(ipa3_res.ipa_hw_type));
Amir Levy9659e592016-10-27 18:08:27 +03004777 if (result) {
4778 IPAERR("Failed to enable GSI FW\n");
4779 release_firmware(fw);
4780 return result;
4781 }
4782
4783 release_firmware(fw);
4784
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004785 IPADBG("Manual FW loading process is complete\n");
Amir Levy9659e592016-10-27 18:08:27 +03004786 return 0;
4787}
4788
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004789static int ipa3_pil_load_ipa_fws(void)
Amir Levy9659e592016-10-27 18:08:27 +03004790{
4791 void *subsystem_get_retval = NULL;
4792
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004793 IPADBG("PIL FW loading process initiated\n");
Amir Levy9659e592016-10-27 18:08:27 +03004794
4795 subsystem_get_retval = subsystem_get(IPA_SUBSYSTEM_NAME);
4796 if (IS_ERR_OR_NULL(subsystem_get_retval)) {
4797 IPAERR("Unable to trigger PIL process for FW loading\n");
4798 return -EINVAL;
4799 }
4800
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004801 IPADBG("PIL FW loading process is complete\n");
Amir Levy9659e592016-10-27 18:08:27 +03004802 return 0;
4803}
4804
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004805static void ipa3_load_ipa_fw(struct work_struct *work)
4806{
4807 int result;
4808
4809 IPADBG("Entry\n");
4810
Skylar Changefc0a0f2018-03-29 11:17:40 -07004811 result = ipa3_attach_to_smmu();
4812 if (result) {
4813 IPAERR("IPA attach to smmu failed %d\n", result);
4814 return;
4815 }
4816
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004817 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
4818
4819 if (ipa3_is_msm_device() || (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5))
4820 result = ipa3_pil_load_ipa_fws();
4821 else
4822 result = ipa3_manual_load_ipa_fws();
4823
4824 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
4825
4826 if (result) {
4827 IPAERR("IPA FW loading process has failed\n");
4828 return;
4829 }
4830 pr_info("IPA FW loaded successfully\n");
4831
Skylar Changefc0a0f2018-03-29 11:17:40 -07004832 result = ipa3_post_init(&ipa3_res, ipa3_ctx->cdev.dev);
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004833 if (result)
4834 IPAERR("IPA post init failed %d\n", result);
4835}
4836
Amir Levy9659e592016-10-27 18:08:27 +03004837static ssize_t ipa3_write(struct file *file, const char __user *buf,
4838 size_t count, loff_t *ppos)
4839{
4840 unsigned long missing;
Amir Levy9659e592016-10-27 18:08:27 +03004841
Amir Levy2da9d452017-12-12 10:09:46 +02004842 char dbg_buff[32] = { 0 };
Amir Levy9659e592016-10-27 18:08:27 +03004843
4844 if (sizeof(dbg_buff) < count + 1)
4845 return -EFAULT;
4846
4847 missing = copy_from_user(dbg_buff, buf, count);
4848
4849 if (missing) {
4850 IPAERR("Unable to copy data from user\n");
4851 return -EFAULT;
4852 }
4853
Amir Levya5774c42017-12-14 22:15:54 +02004854 dbg_buff[count] = '\0';
Mohammed Javidbf4c8022017-08-07 23:15:48 +05304855
Amir Levy2da9d452017-12-12 10:09:46 +02004856 IPADBG("user input string %s\n", dbg_buff);
4857
Amir Levy9659e592016-10-27 18:08:27 +03004858 /* Prevent consequent calls from trying to load the FW again. */
4859 if (ipa3_is_ready())
4860 return count;
4861
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004862 /* Check MHI configuration on MDM devices */
4863 if (!ipa3_is_msm_device()) {
Amir Levy2da9d452017-12-12 10:09:46 +02004864
4865 if (strnstr(dbg_buff, "vlan", strlen(dbg_buff))) {
4866 if (strnstr(dbg_buff, "eth", strlen(dbg_buff)))
4867 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_EMAC] =
4868 true;
4869 if (strnstr(dbg_buff, "rndis", strlen(dbg_buff)))
4870 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_RNDIS] =
4871 true;
4872 if (strnstr(dbg_buff, "ecm", strlen(dbg_buff)))
4873 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM] =
4874 true;
4875
4876 /*
4877 * when vlan mode is passed to our dev we expect
4878 * another write
4879 */
4880 return count;
4881 }
4882
Amir Levya5774c42017-12-14 22:15:54 +02004883 /* trim ending newline character if any */
4884 if (count && (dbg_buff[count - 1] == '\n'))
4885 dbg_buff[count - 1] = '\0';
4886
Amir Levy54fe4d32017-03-16 11:21:49 +02004887 if (!strcasecmp(dbg_buff, "MHI")) {
4888 ipa3_ctx->ipa_config_is_mhi = true;
4889 pr_info(
Amir Levy2da9d452017-12-12 10:09:46 +02004890 "IPA is loading with MHI configuration\n");
Amir Levya5774c42017-12-14 22:15:54 +02004891 } else if (!strcmp(dbg_buff, "1")) {
Amir Levy54fe4d32017-03-16 11:21:49 +02004892 pr_info(
Amir Levy2da9d452017-12-12 10:09:46 +02004893 "IPA is loading with non MHI configuration\n");
4894 } else {
4895 IPAERR("got invalid string %s not loading FW\n",
4896 dbg_buff);
4897 return count;
Amir Levy54fe4d32017-03-16 11:21:49 +02004898 }
Amir Levy54fe4d32017-03-16 11:21:49 +02004899 }
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004900
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004901 queue_work(ipa3_ctx->transport_power_mgmt_wq,
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004902 &ipa3_fw_loading_work);
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004903
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004904 IPADBG("Scheduled a work to load IPA FW\n");
Amir Levy9659e592016-10-27 18:08:27 +03004905 return count;
4906}
4907
Skylar Chang48afa052017-10-25 09:32:57 -07004908/**
4909 * ipa3_tz_unlock_reg - Unlocks memory regions so that they become accessible
4910 * from AP.
4911 * @reg_info - Pointer to array of memory regions to unlock
4912 * @num_regs - Number of elements in the array
4913 *
4914 * Converts the input array of regions to a struct that TZ understands and
4915 * issues an SCM call.
4916 * Also flushes the memory cache to DDR in order to make sure that TZ sees the
4917 * correct data structure.
4918 *
4919 * Returns: 0 on success, negative on failure
4920 */
4921int ipa3_tz_unlock_reg(struct ipa_tz_unlock_reg_info *reg_info, u16 num_regs)
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004922{
4923 int i, size, ret, resp;
4924 struct tz_smmu_ipa_protect_region_iovec_s *ipa_tz_unlock_vec;
4925 struct tz_smmu_ipa_protect_region_s cmd_buf;
Skylar Chang3a696ba2017-10-25 09:35:07 -07004926 struct scm_desc desc = {0};
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004927
Skylar Chang48afa052017-10-25 09:32:57 -07004928 if (reg_info == NULL || num_regs == 0) {
4929 IPAERR("Bad parameters\n");
4930 return -EFAULT;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004931 }
Skylar Chang48afa052017-10-25 09:32:57 -07004932
4933 size = num_regs * sizeof(struct tz_smmu_ipa_protect_region_iovec_s);
4934 ipa_tz_unlock_vec = kzalloc(PAGE_ALIGN(size), GFP_KERNEL);
4935 if (ipa_tz_unlock_vec == NULL)
4936 return -ENOMEM;
4937
4938 for (i = 0; i < num_regs; i++) {
4939 ipa_tz_unlock_vec[i].input_addr = reg_info[i].reg_addr ^
4940 (reg_info[i].reg_addr & 0xFFF);
4941 ipa_tz_unlock_vec[i].output_addr = reg_info[i].reg_addr ^
4942 (reg_info[i].reg_addr & 0xFFF);
4943 ipa_tz_unlock_vec[i].size = reg_info[i].size;
4944 ipa_tz_unlock_vec[i].attr = IPA_TZ_UNLOCK_ATTRIBUTE;
4945 }
4946
4947 /* pass physical address of command buffer */
4948 cmd_buf.iovec_buf = virt_to_phys((void *)ipa_tz_unlock_vec);
4949 cmd_buf.size_bytes = size;
4950
4951 /* flush cache to DDR */
4952 __cpuc_flush_dcache_area((void *)ipa_tz_unlock_vec, size);
4953 outer_flush_range(cmd_buf.iovec_buf, cmd_buf.iovec_buf + size);
Skylar Chang3a696ba2017-10-25 09:35:07 -07004954 if (!is_scm_armv8())
4955 ret = scm_call(SCM_SVC_MP, TZ_MEM_PROTECT_REGION_ID,
4956 &cmd_buf, sizeof(cmd_buf), &resp, sizeof(resp));
4957 else {
4958 desc.args[0] = virt_to_phys((void *)ipa_tz_unlock_vec);
4959 desc.args[1] = size;
4960 desc.arginfo = SCM_ARGS(2, SCM_RO, SCM_VAL);
4961 ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
4962 TZ_MEM_PROTECT_REGION_ID), &desc);
4963 }
Skylar Chang48afa052017-10-25 09:32:57 -07004964
Skylar Chang48afa052017-10-25 09:32:57 -07004965 if (ret) {
4966 IPAERR("scm call SCM_SVC_MP failed: %d\n", ret);
4967 kfree(ipa_tz_unlock_vec);
4968 return -EFAULT;
4969 }
4970 kfree(ipa_tz_unlock_vec);
4971
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004972 return 0;
4973}
4974
Skylar Changcd3902d2017-03-27 18:08:27 -07004975static int ipa3_alloc_pkt_init(void)
4976{
4977 struct ipa_mem_buffer mem;
4978 struct ipahal_imm_cmd_pyld *cmd_pyld;
4979 struct ipahal_imm_cmd_ip_packet_init cmd = {0};
4980 int i;
4981
4982 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
4983 &cmd, false);
4984 if (!cmd_pyld) {
4985 IPAERR("failed to construct IMM cmd\n");
4986 return -ENOMEM;
4987 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -07004988 ipa3_ctx->pkt_init_imm_opcode = cmd_pyld->opcode;
Skylar Changcd3902d2017-03-27 18:08:27 -07004989
4990 mem.size = cmd_pyld->len * ipa3_ctx->ipa_num_pipes;
4991 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
4992 &mem.phys_base, GFP_KERNEL);
4993 if (!mem.base) {
4994 IPAERR("failed to alloc DMA buff of size %d\n", mem.size);
4995 ipahal_destroy_imm_cmd(cmd_pyld);
4996 return -ENOMEM;
4997 }
4998 ipahal_destroy_imm_cmd(cmd_pyld);
4999
5000 memset(mem.base, 0, mem.size);
5001 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
5002 cmd.destination_pipe_index = i;
5003 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
5004 &cmd, false);
5005 if (!cmd_pyld) {
5006 IPAERR("failed to construct IMM cmd\n");
5007 dma_free_coherent(ipa3_ctx->pdev,
5008 mem.size,
5009 mem.base,
5010 mem.phys_base);
5011 return -ENOMEM;
5012 }
5013 memcpy(mem.base + i * cmd_pyld->len, cmd_pyld->data,
5014 cmd_pyld->len);
5015 ipa3_ctx->pkt_init_imm[i] = mem.phys_base + i * cmd_pyld->len;
5016 ipahal_destroy_imm_cmd(cmd_pyld);
5017 }
5018
5019 return 0;
5020}
5021
Amir Levy9659e592016-10-27 18:08:27 +03005022/**
Skylar Chang68c37d82018-04-07 16:42:36 -07005023 * ipa3_pre_init() - Initialize the IPA Driver.
5024 * This part contains all initialization which doesn't require IPA HW, such
5025 * as structure allocations and initializations, register writes, etc.
5026 *
5027 * @resource_p: contain platform specific values from DST file
5028 * @pdev: The platform device structure representing the IPA driver
5029 *
5030 * Function initialization process:
5031 * Allocate memory for the driver context data struct
5032 * Initializing the ipa3_ctx with :
5033 * 1)parsed values from the dts file
5034 * 2)parameters passed to the module initialization
5035 * 3)read HW values(such as core memory size)
5036 * Map IPA core registers to CPU memory
5037 * Restart IPA core(HW reset)
5038 * Initialize the look-aside caches(kmem_cache/slab) for filter,
5039 * routing and IPA-tree
5040 * Create memory pool with 4 objects for DMA operations(each object
5041 * is 512Bytes long), this object will be use for tx(A5->IPA)
5042 * Initialize lists head(routing, hdr, system pipes)
5043 * Initialize mutexes (for ipa_ctx and NAT memory mutexes)
5044 * Initialize spinlocks (for list related to A5<->IPA pipes)
5045 * Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq"
5046 * Initialize Red-Black-Tree(s) for handles of header,routing rule,
5047 * routing table ,filtering rule
5048 * Initialize the filter block by committing IPV4 and IPV6 default rules
5049 * Create empty routing table in system memory(no committing)
5050 * Create a char-device for IPA
5051 * Initialize IPA RM (resource manager)
5052 * Configure GSI registers (in GSI case)
5053 */
Amir Levy9659e592016-10-27 18:08:27 +03005054static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
Skylar Changefc0a0f2018-03-29 11:17:40 -07005055 struct platform_device *ipa_pdev)
Amir Levy9659e592016-10-27 18:08:27 +03005056{
5057 int result = 0;
5058 int i;
Amir Levy9659e592016-10-27 18:08:27 +03005059 struct ipa3_rt_tbl_set *rset;
Mohammed Javidc6db3362018-02-13 13:41:38 +05305060 struct ipa_active_client_logging_info log_info;
Skylar Changefc0a0f2018-03-29 11:17:40 -07005061 struct cdev *cdev;
Amir Levy9659e592016-10-27 18:08:27 +03005062
5063 IPADBG("IPA Driver initialization started\n");
5064
5065 ipa3_ctx = kzalloc(sizeof(*ipa3_ctx), GFP_KERNEL);
5066 if (!ipa3_ctx) {
5067 IPAERR(":kzalloc err.\n");
5068 result = -ENOMEM;
5069 goto fail_mem_ctx;
5070 }
5071
5072 ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0);
Skylar Chang841c1452017-04-03 16:07:22 -07005073 if (ipa3_ctx->logbuf == NULL)
5074 IPAERR("failed to create IPC log, continue...\n");
Amir Levy9659e592016-10-27 18:08:27 +03005075
Skylar Changefc0a0f2018-03-29 11:17:40 -07005076 /* ipa3_ctx->pdev and ipa3_ctx->uc_pdev will be set in the smmu probes*/
5077 ipa3_ctx->master_pdev = ipa_pdev;
Michael Adisumartac8c404a2018-04-05 18:01:45 -07005078 for (i = 0; i < IPA_SMMU_CB_MAX; i++)
5079 ipa3_ctx->s1_bypass_arr[i] = true;
Michael Adisumarta93e97522017-10-06 15:49:46 -07005080
Amir Levy9659e592016-10-27 18:08:27 +03005081 ipa3_ctx->ipa_wrapper_base = resource_p->ipa_mem_base;
5082 ipa3_ctx->ipa_wrapper_size = resource_p->ipa_mem_size;
5083 ipa3_ctx->ipa_hw_type = resource_p->ipa_hw_type;
5084 ipa3_ctx->ipa3_hw_mode = resource_p->ipa3_hw_mode;
5085 ipa3_ctx->use_ipa_teth_bridge = resource_p->use_ipa_teth_bridge;
Amir Levy9659e592016-10-27 18:08:27 +03005086 ipa3_ctx->modem_cfg_emb_pipe_flt = resource_p->modem_cfg_emb_pipe_flt;
5087 ipa3_ctx->ipa_wdi2 = resource_p->ipa_wdi2;
5088 ipa3_ctx->use_64_bit_dma_mask = resource_p->use_64_bit_dma_mask;
5089 ipa3_ctx->wan_rx_ring_size = resource_p->wan_rx_ring_size;
5090 ipa3_ctx->lan_rx_ring_size = resource_p->lan_rx_ring_size;
5091 ipa3_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
5092 ipa3_ctx->tethered_flow_control = resource_p->tethered_flow_control;
Amir Levy9659e592016-10-27 18:08:27 +03005093 ipa3_ctx->ee = resource_p->ee;
5094 ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa;
5095 ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa;
Michael Adisumarta3e350812017-09-18 14:54:36 -07005096 ipa3_ctx->use_ipa_pm = resource_p->use_ipa_pm;
Amir Levy9659e592016-10-27 18:08:27 +03005097 ipa3_ctx->ipa3_active_clients_logging.log_rdy = false;
Mohammed Javid73cd4d22018-04-03 17:15:49 +05305098 ipa3_ctx->ipa_config_is_mhi = resource_p->ipa_mhi_dynamic_config;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005099 ipa3_ctx->mhi_evid_limits[0] = resource_p->mhi_evid_limits[0];
5100 ipa3_ctx->mhi_evid_limits[1] = resource_p->mhi_evid_limits[1];
Skylar Changefc0a0f2018-03-29 11:17:40 -07005101
5102 WARN(ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL,
5103 "Non NORMAL IPA HW mode, is this emulation platform ?");
5104
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005105 if (resource_p->ipa_tz_unlock_reg) {
5106 ipa3_ctx->ipa_tz_unlock_reg_num =
5107 resource_p->ipa_tz_unlock_reg_num;
5108 ipa3_ctx->ipa_tz_unlock_reg = kcalloc(
5109 ipa3_ctx->ipa_tz_unlock_reg_num,
5110 sizeof(*ipa3_ctx->ipa_tz_unlock_reg),
5111 GFP_KERNEL);
5112 if (ipa3_ctx->ipa_tz_unlock_reg == NULL) {
5113 result = -ENOMEM;
5114 goto fail_tz_unlock_reg;
5115 }
5116 for (i = 0; i < ipa3_ctx->ipa_tz_unlock_reg_num; i++) {
5117 ipa3_ctx->ipa_tz_unlock_reg[i].reg_addr =
5118 resource_p->ipa_tz_unlock_reg[i].reg_addr;
5119 ipa3_ctx->ipa_tz_unlock_reg[i].size =
5120 resource_p->ipa_tz_unlock_reg[i].size;
5121 }
5122 }
5123
5124 /* unlock registers for uc */
Skylar Chang48afa052017-10-25 09:32:57 -07005125 result = ipa3_tz_unlock_reg(ipa3_ctx->ipa_tz_unlock_reg,
5126 ipa3_ctx->ipa_tz_unlock_reg_num);
5127 if (result)
5128 IPAERR("Failed to unlock memory region using TZ\n");
Amir Levy9659e592016-10-27 18:08:27 +03005129
5130 /* default aggregation parameters */
5131 ipa3_ctx->aggregation_type = IPA_MBIM_16;
5132 ipa3_ctx->aggregation_byte_limit = 1;
5133 ipa3_ctx->aggregation_time_limit = 0;
5134
5135 ipa3_ctx->ctrl = kzalloc(sizeof(*ipa3_ctx->ctrl), GFP_KERNEL);
5136 if (!ipa3_ctx->ctrl) {
5137 IPAERR("memory allocation error for ctrl\n");
5138 result = -ENOMEM;
5139 goto fail_mem_ctrl;
5140 }
5141 result = ipa3_controller_static_bind(ipa3_ctx->ctrl,
5142 ipa3_ctx->ipa_hw_type);
5143 if (result) {
5144 IPAERR("fail to static bind IPA ctrl.\n");
5145 result = -EFAULT;
5146 goto fail_bind;
5147 }
5148
Skylar Changefc0a0f2018-03-29 11:17:40 -07005149 result = ipa3_init_mem_partition(ipa3_ctx->master_pdev->dev.of_node);
Amir Levy9659e592016-10-27 18:08:27 +03005150 if (result) {
5151 IPAERR(":ipa3_init_mem_partition failed!\n");
5152 result = -ENODEV;
5153 goto fail_init_mem_partition;
5154 }
5155
Skylar Changefc0a0f2018-03-29 11:17:40 -07005156 if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_VIRTUAL) {
5157 ipa3_ctx->ctrl->msm_bus_data_ptr =
5158 msm_bus_cl_get_pdata(ipa3_ctx->master_pdev);
5159 if (ipa3_ctx->ctrl->msm_bus_data_ptr == NULL) {
5160 IPAERR("failed to get bus scaling\n");
5161 goto fail_bus_reg;
5162 }
Ghanim Fodi6a831342017-03-07 18:19:15 +02005163 IPADBG("Use bus scaling info from device tree #usecases=%d\n",
Skylar Changefc0a0f2018-03-29 11:17:40 -07005164 ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases);
Amir Levy9659e592016-10-27 18:08:27 +03005165
Skylar Changefc0a0f2018-03-29 11:17:40 -07005166 /* get BUS handle */
5167 ipa3_ctx->ipa_bus_hdl =
5168 msm_bus_scale_register_client(
5169 ipa3_ctx->ctrl->msm_bus_data_ptr);
5170 if (!ipa3_ctx->ipa_bus_hdl) {
5171 IPAERR("fail to register with bus mgr!\n");
5172 result = -ENODEV;
5173 goto fail_bus_reg;
5174 }
Amir Levy9659e592016-10-27 18:08:27 +03005175 }
5176
5177 /* get IPA clocks */
Skylar Changefc0a0f2018-03-29 11:17:40 -07005178 result = ipa3_get_clks(&ipa3_ctx->master_pdev->dev);
Amir Levy9659e592016-10-27 18:08:27 +03005179 if (result)
5180 goto fail_clk;
5181
5182 /* init active_clients_log after getting ipa-clk */
Ghanim Fodic48ba992017-12-24 19:28:38 +02005183 result = ipa3_active_clients_log_init();
5184 if (result)
Amir Levy9659e592016-10-27 18:08:27 +03005185 goto fail_init_active_client;
5186
5187 /* Enable ipa3_ctx->enable_clock_scaling */
5188 ipa3_ctx->enable_clock_scaling = 1;
5189 ipa3_ctx->curr_ipa_clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
5190
5191 /* enable IPA clocks explicitly to allow the initialization */
5192 ipa3_enable_clks();
5193
5194 /* setup IPA register access */
5195 IPADBG("Mapping 0x%x\n", resource_p->ipa_mem_base +
5196 ipa3_ctx->ctrl->ipa_reg_base_ofst);
5197 ipa3_ctx->mmio = ioremap(resource_p->ipa_mem_base +
5198 ipa3_ctx->ctrl->ipa_reg_base_ofst,
5199 resource_p->ipa_mem_size);
5200 if (!ipa3_ctx->mmio) {
5201 IPAERR(":ipa-base ioremap err.\n");
5202 result = -EFAULT;
5203 goto fail_remap;
5204 }
5205
Amir Levy9659e592016-10-27 18:08:27 +03005206 mutex_init(&ipa3_ctx->ipa3_active_clients.mutex);
Mohammed Javidc6db3362018-02-13 13:41:38 +05305207
5208 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE");
5209 ipa3_active_clients_log_inc(&log_info, false);
5210 ipa3_ctx->q6_proxy_clk_vote_valid = true;
5211 ipa3_ctx->q6_proxy_clk_vote_cnt = 1;
5212
5213 /*Updating the proxy vote cnt 1 */
Skylar Chang242952b2017-07-20 15:04:05 -07005214 atomic_set(&ipa3_ctx->ipa3_active_clients.cnt, 1);
Amir Levy9659e592016-10-27 18:08:27 +03005215
Amir Levy9659e592016-10-27 18:08:27 +03005216 /* Create workqueues for power management */
5217 ipa3_ctx->power_mgmt_wq =
5218 create_singlethread_workqueue("ipa_power_mgmt");
5219 if (!ipa3_ctx->power_mgmt_wq) {
5220 IPAERR("failed to create power mgmt wq\n");
5221 result = -ENOMEM;
5222 goto fail_init_hw;
5223 }
5224
5225 ipa3_ctx->transport_power_mgmt_wq =
5226 create_singlethread_workqueue("transport_power_mgmt");
5227 if (!ipa3_ctx->transport_power_mgmt_wq) {
5228 IPAERR("failed to create transport power mgmt wq\n");
5229 result = -ENOMEM;
5230 goto fail_create_transport_wq;
5231 }
5232
Sridhar Ancha99b505b2016-04-21 23:11:10 +05305233 mutex_init(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03005234
5235 /* init the lookaside cache */
5236 ipa3_ctx->flt_rule_cache = kmem_cache_create("IPA_FLT",
5237 sizeof(struct ipa3_flt_entry), 0, 0, NULL);
5238 if (!ipa3_ctx->flt_rule_cache) {
5239 IPAERR(":ipa flt cache create failed\n");
5240 result = -ENOMEM;
5241 goto fail_flt_rule_cache;
5242 }
5243 ipa3_ctx->rt_rule_cache = kmem_cache_create("IPA_RT",
5244 sizeof(struct ipa3_rt_entry), 0, 0, NULL);
5245 if (!ipa3_ctx->rt_rule_cache) {
5246 IPAERR(":ipa rt cache create failed\n");
5247 result = -ENOMEM;
5248 goto fail_rt_rule_cache;
5249 }
5250 ipa3_ctx->hdr_cache = kmem_cache_create("IPA_HDR",
5251 sizeof(struct ipa3_hdr_entry), 0, 0, NULL);
5252 if (!ipa3_ctx->hdr_cache) {
5253 IPAERR(":ipa hdr cache create failed\n");
5254 result = -ENOMEM;
5255 goto fail_hdr_cache;
5256 }
5257 ipa3_ctx->hdr_offset_cache =
5258 kmem_cache_create("IPA_HDR_OFFSET",
5259 sizeof(struct ipa_hdr_offset_entry), 0, 0, NULL);
5260 if (!ipa3_ctx->hdr_offset_cache) {
5261 IPAERR(":ipa hdr off cache create failed\n");
5262 result = -ENOMEM;
5263 goto fail_hdr_offset_cache;
5264 }
5265 ipa3_ctx->hdr_proc_ctx_cache = kmem_cache_create("IPA_HDR_PROC_CTX",
5266 sizeof(struct ipa3_hdr_proc_ctx_entry), 0, 0, NULL);
5267 if (!ipa3_ctx->hdr_proc_ctx_cache) {
5268 IPAERR(":ipa hdr proc ctx cache create failed\n");
5269 result = -ENOMEM;
5270 goto fail_hdr_proc_ctx_cache;
5271 }
5272 ipa3_ctx->hdr_proc_ctx_offset_cache =
5273 kmem_cache_create("IPA_HDR_PROC_CTX_OFFSET",
5274 sizeof(struct ipa3_hdr_proc_ctx_offset_entry), 0, 0, NULL);
5275 if (!ipa3_ctx->hdr_proc_ctx_offset_cache) {
5276 IPAERR(":ipa hdr proc ctx off cache create failed\n");
5277 result = -ENOMEM;
5278 goto fail_hdr_proc_ctx_offset_cache;
5279 }
5280 ipa3_ctx->rt_tbl_cache = kmem_cache_create("IPA_RT_TBL",
5281 sizeof(struct ipa3_rt_tbl), 0, 0, NULL);
5282 if (!ipa3_ctx->rt_tbl_cache) {
5283 IPAERR(":ipa rt tbl cache create failed\n");
5284 result = -ENOMEM;
5285 goto fail_rt_tbl_cache;
5286 }
5287 ipa3_ctx->tx_pkt_wrapper_cache =
5288 kmem_cache_create("IPA_TX_PKT_WRAPPER",
5289 sizeof(struct ipa3_tx_pkt_wrapper), 0, 0, NULL);
5290 if (!ipa3_ctx->tx_pkt_wrapper_cache) {
5291 IPAERR(":ipa tx pkt wrapper cache create failed\n");
5292 result = -ENOMEM;
5293 goto fail_tx_pkt_wrapper_cache;
5294 }
5295 ipa3_ctx->rx_pkt_wrapper_cache =
5296 kmem_cache_create("IPA_RX_PKT_WRAPPER",
5297 sizeof(struct ipa3_rx_pkt_wrapper), 0, 0, NULL);
5298 if (!ipa3_ctx->rx_pkt_wrapper_cache) {
5299 IPAERR(":ipa rx pkt wrapper cache create failed\n");
5300 result = -ENOMEM;
5301 goto fail_rx_pkt_wrapper_cache;
5302 }
5303
Amir Levy9659e592016-10-27 18:08:27 +03005304 /* init the various list heads */
5305 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_hdr_entry_list);
5306 for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
5307 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_offset_list[i]);
5308 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_free_offset_list[i]);
5309 }
5310 INIT_LIST_HEAD(&ipa3_ctx->hdr_proc_ctx_tbl.head_proc_ctx_entry_list);
5311 for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) {
5312 INIT_LIST_HEAD(&ipa3_ctx->hdr_proc_ctx_tbl.head_offset_list[i]);
5313 INIT_LIST_HEAD(&ipa3_ctx->
5314 hdr_proc_ctx_tbl.head_free_offset_list[i]);
5315 }
5316 INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005317 idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005318 INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005319 idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005320
5321 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
5322 INIT_LIST_HEAD(&rset->head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005323 idr_init(&rset->rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005324 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
5325 INIT_LIST_HEAD(&rset->head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005326 idr_init(&rset->rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005327
5328 INIT_LIST_HEAD(&ipa3_ctx->intf_list);
5329 INIT_LIST_HEAD(&ipa3_ctx->msg_list);
5330 INIT_LIST_HEAD(&ipa3_ctx->pull_msg_list);
5331 init_waitqueue_head(&ipa3_ctx->msg_waitq);
5332 mutex_init(&ipa3_ctx->msg_lock);
5333
Skylar Chang68c37d82018-04-07 16:42:36 -07005334 /* store wlan client-connect-msg-list */
5335 INIT_LIST_HEAD(&ipa3_ctx->msg_wlan_client_list);
5336 mutex_init(&ipa3_ctx->msg_wlan_client_lock);
5337
Amir Levy9659e592016-10-27 18:08:27 +03005338 mutex_init(&ipa3_ctx->lock);
Skylar Changfb792c62017-08-17 12:53:23 -07005339 mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex);
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05305340 mutex_init(&ipa3_ctx->ipa_cne_evt_lock);
Amir Levy9659e592016-10-27 18:08:27 +03005341
5342 idr_init(&ipa3_ctx->ipa_idr);
5343 spin_lock_init(&ipa3_ctx->idr_lock);
5344
5345 /* wlan related member */
5346 memset(&ipa3_ctx->wc_memb, 0, sizeof(ipa3_ctx->wc_memb));
5347 spin_lock_init(&ipa3_ctx->wc_memb.wlan_spinlock);
5348 spin_lock_init(&ipa3_ctx->wc_memb.ipa_tx_mul_spinlock);
5349 INIT_LIST_HEAD(&ipa3_ctx->wc_memb.wlan_comm_desc_list);
5350
Skylar Changefc0a0f2018-03-29 11:17:40 -07005351 ipa3_ctx->cdev.class = class_create(THIS_MODULE, DRV_NAME);
Amir Levy9659e592016-10-27 18:08:27 +03005352
Skylar Changefc0a0f2018-03-29 11:17:40 -07005353 result = alloc_chrdev_region(&ipa3_ctx->cdev.dev_num, 0, 1, DRV_NAME);
Amir Levy9659e592016-10-27 18:08:27 +03005354 if (result) {
5355 IPAERR("alloc_chrdev_region err.\n");
5356 result = -ENODEV;
5357 goto fail_alloc_chrdev_region;
5358 }
5359
Skylar Changefc0a0f2018-03-29 11:17:40 -07005360 ipa3_ctx->cdev.dev = device_create(ipa3_ctx->cdev.class, NULL,
5361 ipa3_ctx->cdev.dev_num, ipa3_ctx, DRV_NAME);
5362 if (IS_ERR(ipa3_ctx->cdev.dev)) {
Amir Levy9659e592016-10-27 18:08:27 +03005363 IPAERR(":device_create err.\n");
5364 result = -ENODEV;
5365 goto fail_device_create;
5366 }
5367
Amir Levy9659e592016-10-27 18:08:27 +03005368 /* Create a wakeup source. */
5369 wakeup_source_init(&ipa3_ctx->w_lock, "IPA_WS");
5370 spin_lock_init(&ipa3_ctx->wakelock_ref_cnt.spinlock);
5371
Michael Adisumarta3e350812017-09-18 14:54:36 -07005372 /* Initialize Power Management framework */
5373 if (ipa3_ctx->use_ipa_pm) {
5374 result = ipa_pm_init(&ipa3_res.pm_init);
5375 if (result) {
5376 IPAERR("IPA PM initialization failed (%d)\n", -result);
5377 result = -ENODEV;
5378 goto fail_ipa_rm_init;
5379 }
5380 IPADBG("IPA resource manager initialized");
5381 } else {
5382 result = ipa_rm_initialize();
5383 if (result) {
5384 IPAERR("RM initialization failed (%d)\n", -result);
5385 result = -ENODEV;
5386 goto fail_ipa_rm_init;
5387 }
5388 IPADBG("IPA resource manager initialized");
Amir Levy9659e592016-10-27 18:08:27 +03005389
Michael Adisumarta3e350812017-09-18 14:54:36 -07005390 result = ipa3_create_apps_resource();
5391 if (result) {
5392 IPAERR("Failed to create APPS_CONS resource\n");
5393 result = -ENODEV;
5394 goto fail_create_apps_resource;
5395 }
Amir Levy9659e592016-10-27 18:08:27 +03005396 }
5397
Amir Levy9659e592016-10-27 18:08:27 +03005398 INIT_LIST_HEAD(&ipa3_ctx->ipa_ready_cb_list);
5399
5400 init_completion(&ipa3_ctx->init_completion_obj);
Skylar Chang0c17c7d2016-10-31 09:57:54 -07005401 init_completion(&ipa3_ctx->uc_loaded_completion_obj);
Amir Levy9659e592016-10-27 18:08:27 +03005402
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005403 result = ipa3_dma_setup();
5404 if (result) {
5405 IPAERR("Failed to setup IPA DMA\n");
5406 result = -ENODEV;
5407 goto fail_ipa_dma_setup;
5408 }
5409
Amir Levy9659e592016-10-27 18:08:27 +03005410 /*
Amir Levya59ed3f2017-03-05 17:30:55 +02005411 * We can't register the GSI driver yet, as it expects
Amir Levy9659e592016-10-27 18:08:27 +03005412 * the GSI FW to be up and running before the registration.
Amir Levya59ed3f2017-03-05 17:30:55 +02005413 *
5414 * For IPA3.0, the GSI configuration is done by the GSI driver.
5415 * For IPA3.1 (and on), the GSI configuration is done by TZ.
Amir Levy9659e592016-10-27 18:08:27 +03005416 */
Amir Levya59ed3f2017-03-05 17:30:55 +02005417 if (ipa3_ctx->ipa_hw_type == IPA_HW_v3_0) {
5418 result = ipa3_gsi_pre_fw_load_init();
5419 if (result) {
5420 IPAERR("gsi pre FW loading config failed\n");
5421 result = -ENODEV;
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005422 goto fail_gsi_pre_fw_load_init;
Amir Levy9659e592016-10-27 18:08:27 +03005423 }
5424 }
Amir Levy9659e592016-10-27 18:08:27 +03005425
Skylar Changefc0a0f2018-03-29 11:17:40 -07005426 cdev = &ipa3_ctx->cdev.cdev;
5427 cdev_init(cdev, &ipa3_drv_fops);
5428 cdev->owner = THIS_MODULE;
5429 cdev->ops = &ipa3_drv_fops; /* from LDD3 */
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305430
Skylar Changefc0a0f2018-03-29 11:17:40 -07005431 result = cdev_add(cdev, ipa3_ctx->cdev.dev_num, 1);
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305432 if (result) {
5433 IPAERR(":cdev_add err=%d\n", -result);
5434 result = -ENODEV;
5435 goto fail_cdev_add;
5436 }
5437 IPADBG("ipa cdev added successful. major:%d minor:%d\n",
Skylar Changefc0a0f2018-03-29 11:17:40 -07005438 MAJOR(ipa3_ctx->cdev.dev_num),
5439 MINOR(ipa3_ctx->cdev.dev_num));
Mohammed Javidc6db3362018-02-13 13:41:38 +05305440 /*
5441 * for IPA 4.0 offline charge is not needed and we need to prevent
5442 * power collapse until IPA uC is loaded.
5443 */
5444
Skylar Chang40430532017-07-06 14:31:57 -07005445 /* proxy vote for modem is added in ipa3_post_init() phase */
Mohammed Javidc6db3362018-02-13 13:41:38 +05305446 if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0)
5447 ipa3_proxy_clk_unvote();
Amir Levy9659e592016-10-27 18:08:27 +03005448 return 0;
5449
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305450fail_cdev_add:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005451fail_gsi_pre_fw_load_init:
5452 ipa3_dma_shutdown();
5453fail_ipa_dma_setup:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005454 if (ipa3_ctx->use_ipa_pm)
5455 ipa_pm_destroy();
5456 else
Michael Adisumarta3e350812017-09-18 14:54:36 -07005457 ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
Amir Levy9659e592016-10-27 18:08:27 +03005458fail_create_apps_resource:
Michael Adisumarta3e350812017-09-18 14:54:36 -07005459 if (!ipa3_ctx->use_ipa_pm)
5460 ipa_rm_exit();
Amir Levy9659e592016-10-27 18:08:27 +03005461fail_ipa_rm_init:
Skylar Changefc0a0f2018-03-29 11:17:40 -07005462 device_destroy(ipa3_ctx->cdev.class, ipa3_ctx->cdev.dev_num);
Amir Levy9659e592016-10-27 18:08:27 +03005463fail_device_create:
Skylar Changefc0a0f2018-03-29 11:17:40 -07005464 unregister_chrdev_region(ipa3_ctx->cdev.dev_num, 1);
Amir Levy9659e592016-10-27 18:08:27 +03005465fail_alloc_chrdev_region:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005466 idr_destroy(&ipa3_ctx->ipa_idr);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005467 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
5468 idr_destroy(&rset->rule_ids);
5469 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
5470 idr_destroy(&rset->rule_ids);
5471 idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
5472 idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005473 kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
5474fail_rx_pkt_wrapper_cache:
5475 kmem_cache_destroy(ipa3_ctx->tx_pkt_wrapper_cache);
5476fail_tx_pkt_wrapper_cache:
5477 kmem_cache_destroy(ipa3_ctx->rt_tbl_cache);
5478fail_rt_tbl_cache:
5479 kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_offset_cache);
5480fail_hdr_proc_ctx_offset_cache:
5481 kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_cache);
5482fail_hdr_proc_ctx_cache:
5483 kmem_cache_destroy(ipa3_ctx->hdr_offset_cache);
5484fail_hdr_offset_cache:
5485 kmem_cache_destroy(ipa3_ctx->hdr_cache);
5486fail_hdr_cache:
5487 kmem_cache_destroy(ipa3_ctx->rt_rule_cache);
5488fail_rt_rule_cache:
5489 kmem_cache_destroy(ipa3_ctx->flt_rule_cache);
5490fail_flt_rule_cache:
5491 destroy_workqueue(ipa3_ctx->transport_power_mgmt_wq);
5492fail_create_transport_wq:
5493 destroy_workqueue(ipa3_ctx->power_mgmt_wq);
5494fail_init_hw:
Amir Levy9659e592016-10-27 18:08:27 +03005495 iounmap(ipa3_ctx->mmio);
5496fail_remap:
5497 ipa3_disable_clks();
5498 ipa3_active_clients_log_destroy();
5499fail_init_active_client:
Ghanim Fodi6a831342017-03-07 18:19:15 +02005500 if (ipa3_clk)
5501 clk_put(ipa3_clk);
5502 ipa3_clk = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03005503fail_clk:
Skylar Changefc0a0f2018-03-29 11:17:40 -07005504 if (ipa3_ctx->ipa_bus_hdl)
5505 msm_bus_scale_unregister_client(ipa3_ctx->ipa_bus_hdl);
Amir Levy9659e592016-10-27 18:08:27 +03005506fail_bus_reg:
Skylar Changefc0a0f2018-03-29 11:17:40 -07005507 if (ipa3_ctx->ctrl->msm_bus_data_ptr)
5508 msm_bus_cl_clear_pdata(ipa3_ctx->ctrl->msm_bus_data_ptr);
Amir Levy9659e592016-10-27 18:08:27 +03005509fail_init_mem_partition:
5510fail_bind:
5511 kfree(ipa3_ctx->ctrl);
5512fail_mem_ctrl:
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005513 kfree(ipa3_ctx->ipa_tz_unlock_reg);
5514fail_tz_unlock_reg:
Skylar Chang841c1452017-04-03 16:07:22 -07005515 if (ipa3_ctx->logbuf)
5516 ipc_log_context_destroy(ipa3_ctx->logbuf);
Amir Levy9659e592016-10-27 18:08:27 +03005517 kfree(ipa3_ctx);
5518 ipa3_ctx = NULL;
5519fail_mem_ctx:
5520 return result;
5521}
5522
Michael Adisumarta3e350812017-09-18 14:54:36 -07005523static int get_ipa_dts_pm_info(struct platform_device *pdev,
5524 struct ipa3_plat_drv_res *ipa_drv_res)
5525{
5526 int result;
5527 int i, j;
5528
5529 ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
5530 "qcom,use-ipa-pm");
5531 IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
5532 if (!ipa_drv_res->use_ipa_pm)
5533 return 0;
5534
5535 result = of_property_read_u32(pdev->dev.of_node,
5536 "qcom,msm-bus,num-cases",
5537 &ipa_drv_res->pm_init.threshold_size);
5538 /* No vote is ignored */
5539 ipa_drv_res->pm_init.threshold_size -= 2;
5540 if (result || ipa_drv_res->pm_init.threshold_size >
5541 IPA_PM_THRESHOLD_MAX) {
5542 IPAERR("invalid property qcom,msm-bus,num-cases %d\n",
5543 ipa_drv_res->pm_init.threshold_size);
5544 return -EFAULT;
5545 }
5546
5547 result = of_property_read_u32_array(pdev->dev.of_node,
5548 "qcom,throughput-threshold",
5549 ipa_drv_res->pm_init.default_threshold,
5550 ipa_drv_res->pm_init.threshold_size);
5551 if (result) {
5552 IPAERR("failed to read qcom,throughput-thresholds\n");
5553 return -EFAULT;
5554 }
5555
5556 result = of_property_count_strings(pdev->dev.of_node,
5557 "qcom,scaling-exceptions");
5558 if (result < 0) {
5559 IPADBG("no exception list for ipa pm\n");
5560 result = 0;
5561 }
5562
5563 if (result % (ipa_drv_res->pm_init.threshold_size + 1)) {
5564 IPAERR("failed to read qcom,scaling-exceptions\n");
5565 return -EFAULT;
5566 }
5567
5568 ipa_drv_res->pm_init.exception_size = result /
5569 (ipa_drv_res->pm_init.threshold_size + 1);
5570 if (ipa_drv_res->pm_init.exception_size >=
5571 IPA_PM_EXCEPTION_MAX) {
5572 IPAERR("exception list larger then max %d\n",
5573 ipa_drv_res->pm_init.exception_size);
5574 return -EFAULT;
5575 }
5576
5577 for (i = 0; i < ipa_drv_res->pm_init.exception_size; i++) {
5578 struct ipa_pm_exception *ex = ipa_drv_res->pm_init.exceptions;
5579
5580 result = of_property_read_string_index(pdev->dev.of_node,
5581 "qcom,scaling-exceptions",
5582 i * ipa_drv_res->pm_init.threshold_size,
5583 &ex[i].usecase);
5584 if (result) {
5585 IPAERR("failed to read qcom,scaling-exceptions");
5586 return -EFAULT;
5587 }
5588
5589 for (j = 0; j < ipa_drv_res->pm_init.threshold_size; j++) {
5590 const char *str;
5591
5592 result = of_property_read_string_index(
5593 pdev->dev.of_node,
5594 "qcom,scaling-exceptions",
5595 i * ipa_drv_res->pm_init.threshold_size + j + 1,
5596 &str);
5597 if (result) {
5598 IPAERR("failed to read qcom,scaling-exceptions"
5599 );
5600 return -EFAULT;
5601 }
5602
5603 if (kstrtou32(str, 0, &ex[i].threshold[j])) {
5604 IPAERR("error str=%s\n", str);
5605 return -EFAULT;
5606 }
5607 }
5608 }
5609
5610 return 0;
5611}
5612
Amir Levy9659e592016-10-27 18:08:27 +03005613static int get_ipa_dts_configuration(struct platform_device *pdev,
5614 struct ipa3_plat_drv_res *ipa_drv_res)
5615{
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005616 int i, result, pos;
Amir Levy9659e592016-10-27 18:08:27 +03005617 struct resource *resource;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005618 u32 *ipa_tz_unlock_reg;
5619 int elem_num;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005620 u32 mhi_evid_limits[2];
Amir Levy9659e592016-10-27 18:08:27 +03005621
5622 /* initialize ipa3_res */
5623 ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
5624 ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
5625 ipa_drv_res->ipa_hw_type = 0;
5626 ipa_drv_res->ipa3_hw_mode = 0;
Amir Levy9659e592016-10-27 18:08:27 +03005627 ipa_drv_res->modem_cfg_emb_pipe_flt = false;
5628 ipa_drv_res->ipa_wdi2 = false;
Mohammed Javid73cd4d22018-04-03 17:15:49 +05305629 ipa_drv_res->ipa_mhi_dynamic_config = false;
Amir Levy9659e592016-10-27 18:08:27 +03005630 ipa_drv_res->use_64_bit_dma_mask = false;
Ghanim Fodi6a831342017-03-07 18:19:15 +02005631 ipa_drv_res->use_bw_vote = false;
Amir Levy9659e592016-10-27 18:08:27 +03005632 ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
5633 ipa_drv_res->lan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
5634 ipa_drv_res->apply_rg10_wa = false;
5635 ipa_drv_res->gsi_ch20_wa = false;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005636 ipa_drv_res->ipa_tz_unlock_reg_num = 0;
5637 ipa_drv_res->ipa_tz_unlock_reg = NULL;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005638 ipa_drv_res->mhi_evid_limits[0] = IPA_MHI_GSI_EVENT_RING_ID_START;
5639 ipa_drv_res->mhi_evid_limits[1] = IPA_MHI_GSI_EVENT_RING_ID_END;
Amir Levy9659e592016-10-27 18:08:27 +03005640
5641 /* Get IPA HW Version */
5642 result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver",
5643 &ipa_drv_res->ipa_hw_type);
5644 if ((result) || (ipa_drv_res->ipa_hw_type == 0)) {
5645 IPAERR(":get resource failed for ipa-hw-ver!\n");
5646 return -ENODEV;
5647 }
5648 IPADBG(": ipa_hw_type = %d", ipa_drv_res->ipa_hw_type);
5649
5650 if (ipa_drv_res->ipa_hw_type < IPA_HW_v3_0) {
5651 IPAERR(":IPA version below 3.0 not supported!\n");
5652 return -ENODEV;
5653 }
5654
5655 /* Get IPA HW mode */
5656 result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-mode",
5657 &ipa_drv_res->ipa3_hw_mode);
5658 if (result)
5659 IPADBG("using default (IPA_MODE_NORMAL) for ipa-hw-mode\n");
5660 else
5661 IPADBG(": found ipa_drv_res->ipa3_hw_mode = %d",
5662 ipa_drv_res->ipa3_hw_mode);
5663
5664 /* Get IPA WAN / LAN RX pool size */
5665 result = of_property_read_u32(pdev->dev.of_node,
5666 "qcom,wan-rx-ring-size",
5667 &ipa_drv_res->wan_rx_ring_size);
5668 if (result)
5669 IPADBG("using default for wan-rx-ring-size = %u\n",
5670 ipa_drv_res->wan_rx_ring_size);
5671 else
5672 IPADBG(": found ipa_drv_res->wan-rx-ring-size = %u",
5673 ipa_drv_res->wan_rx_ring_size);
5674
5675 result = of_property_read_u32(pdev->dev.of_node,
5676 "qcom,lan-rx-ring-size",
5677 &ipa_drv_res->lan_rx_ring_size);
5678 if (result)
5679 IPADBG("using default for lan-rx-ring-size = %u\n",
5680 ipa_drv_res->lan_rx_ring_size);
5681 else
5682 IPADBG(": found ipa_drv_res->lan-rx-ring-size = %u",
5683 ipa_drv_res->lan_rx_ring_size);
5684
5685 ipa_drv_res->use_ipa_teth_bridge =
5686 of_property_read_bool(pdev->dev.of_node,
5687 "qcom,use-ipa-tethering-bridge");
5688 IPADBG(": using TBDr = %s",
5689 ipa_drv_res->use_ipa_teth_bridge
5690 ? "True" : "False");
5691
Mohammed Javid73cd4d22018-04-03 17:15:49 +05305692 ipa_drv_res->ipa_mhi_dynamic_config =
5693 of_property_read_bool(pdev->dev.of_node,
5694 "qcom,use-ipa-in-mhi-mode");
5695 IPADBG(": ipa_mhi_dynamic_config (%s)\n",
5696 ipa_drv_res->ipa_mhi_dynamic_config
5697 ? "True" : "False");
5698
Amir Levy9659e592016-10-27 18:08:27 +03005699 ipa_drv_res->modem_cfg_emb_pipe_flt =
5700 of_property_read_bool(pdev->dev.of_node,
5701 "qcom,modem-cfg-emb-pipe-flt");
5702 IPADBG(": modem configure embedded pipe filtering = %s\n",
5703 ipa_drv_res->modem_cfg_emb_pipe_flt
5704 ? "True" : "False");
5705
5706 ipa_drv_res->ipa_wdi2 =
5707 of_property_read_bool(pdev->dev.of_node,
5708 "qcom,ipa-wdi2");
5709 IPADBG(": WDI-2.0 = %s\n",
5710 ipa_drv_res->ipa_wdi2
5711 ? "True" : "False");
5712
5713 ipa_drv_res->use_64_bit_dma_mask =
5714 of_property_read_bool(pdev->dev.of_node,
5715 "qcom,use-64-bit-dma-mask");
5716 IPADBG(": use_64_bit_dma_mask = %s\n",
5717 ipa_drv_res->use_64_bit_dma_mask
5718 ? "True" : "False");
5719
Ghanim Fodi6a831342017-03-07 18:19:15 +02005720 ipa_drv_res->use_bw_vote =
5721 of_property_read_bool(pdev->dev.of_node,
5722 "qcom,bandwidth-vote-for-ipa");
5723 IPADBG(": use_bw_vote = %s\n",
5724 ipa_drv_res->use_bw_vote
5725 ? "True" : "False");
5726
Amir Levy9659e592016-10-27 18:08:27 +03005727 ipa_drv_res->skip_uc_pipe_reset =
5728 of_property_read_bool(pdev->dev.of_node,
5729 "qcom,skip-uc-pipe-reset");
5730 IPADBG(": skip uC pipe reset = %s\n",
5731 ipa_drv_res->skip_uc_pipe_reset
5732 ? "True" : "False");
5733
5734 ipa_drv_res->tethered_flow_control =
5735 of_property_read_bool(pdev->dev.of_node,
5736 "qcom,tethered-flow-control");
5737 IPADBG(": Use apps based flow control = %s\n",
5738 ipa_drv_res->tethered_flow_control
5739 ? "True" : "False");
5740
Amir Levy9659e592016-10-27 18:08:27 +03005741 /* Get IPA wrapper address */
5742 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5743 "ipa-base");
5744 if (!resource) {
5745 IPAERR(":get resource failed for ipa-base!\n");
5746 return -ENODEV;
5747 }
5748 ipa_drv_res->ipa_mem_base = resource->start;
5749 ipa_drv_res->ipa_mem_size = resource_size(resource);
5750 IPADBG(": ipa-base = 0x%x, size = 0x%x\n",
5751 ipa_drv_res->ipa_mem_base,
5752 ipa_drv_res->ipa_mem_size);
5753
5754 smmu_info.ipa_base = ipa_drv_res->ipa_mem_base;
5755 smmu_info.ipa_size = ipa_drv_res->ipa_mem_size;
5756
Amir Levya59ed3f2017-03-05 17:30:55 +02005757 /* Get IPA GSI address */
5758 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5759 "gsi-base");
5760 if (!resource) {
5761 IPAERR(":get resource failed for gsi-base!\n");
5762 return -ENODEV;
Amir Levy9659e592016-10-27 18:08:27 +03005763 }
Amir Levya59ed3f2017-03-05 17:30:55 +02005764 ipa_drv_res->transport_mem_base = resource->start;
5765 ipa_drv_res->transport_mem_size = resource_size(resource);
5766 IPADBG(": gsi-base = 0x%x, size = 0x%x\n",
5767 ipa_drv_res->transport_mem_base,
5768 ipa_drv_res->transport_mem_size);
5769
5770 /* Get IPA GSI IRQ number */
5771 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
5772 "gsi-irq");
5773 if (!resource) {
5774 IPAERR(":get resource failed for gsi-irq!\n");
5775 return -ENODEV;
5776 }
5777 ipa_drv_res->transport_irq = resource->start;
5778 IPADBG(": gsi-irq = %d\n", ipa_drv_res->transport_irq);
Amir Levy9659e592016-10-27 18:08:27 +03005779
5780 /* Get IPA pipe mem start ofst */
5781 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5782 "ipa-pipe-mem");
5783 if (!resource) {
5784 IPADBG(":not using pipe memory - resource nonexisting\n");
5785 } else {
5786 ipa_drv_res->ipa_pipe_mem_start_ofst = resource->start;
5787 ipa_drv_res->ipa_pipe_mem_size = resource_size(resource);
5788 IPADBG(":using pipe memory - at 0x%x of size 0x%x\n",
5789 ipa_drv_res->ipa_pipe_mem_start_ofst,
5790 ipa_drv_res->ipa_pipe_mem_size);
5791 }
5792
5793 /* Get IPA IRQ number */
5794 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
5795 "ipa-irq");
5796 if (!resource) {
5797 IPAERR(":get resource failed for ipa-irq!\n");
5798 return -ENODEV;
5799 }
5800 ipa_drv_res->ipa_irq = resource->start;
5801 IPADBG(":ipa-irq = %d\n", ipa_drv_res->ipa_irq);
5802
5803 result = of_property_read_u32(pdev->dev.of_node, "qcom,ee",
5804 &ipa_drv_res->ee);
5805 if (result)
5806 ipa_drv_res->ee = 0;
5807
5808 ipa_drv_res->apply_rg10_wa =
5809 of_property_read_bool(pdev->dev.of_node,
5810 "qcom,use-rg10-limitation-mitigation");
5811 IPADBG(": Use Register Group 10 limitation mitigation = %s\n",
5812 ipa_drv_res->apply_rg10_wa
5813 ? "True" : "False");
5814
5815 ipa_drv_res->gsi_ch20_wa =
5816 of_property_read_bool(pdev->dev.of_node,
5817 "qcom,do-not-use-ch-gsi-20");
5818 IPADBG(": GSI CH 20 WA is = %s\n",
5819 ipa_drv_res->apply_rg10_wa
5820 ? "Needed" : "Not needed");
5821
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005822 elem_num = of_property_count_elems_of_size(pdev->dev.of_node,
Ghanim Fodic823bc62017-10-21 17:29:53 +03005823 "qcom,mhi-event-ring-id-limits", sizeof(u32));
5824
5825 if (elem_num == 2) {
5826 if (of_property_read_u32_array(pdev->dev.of_node,
5827 "qcom,mhi-event-ring-id-limits", mhi_evid_limits, 2)) {
5828 IPAERR("failed to read mhi event ring id limits\n");
5829 return -EFAULT;
5830 }
5831 if (mhi_evid_limits[0] > mhi_evid_limits[1]) {
5832 IPAERR("mhi event ring id low limit > high limit\n");
5833 return -EFAULT;
5834 }
5835 ipa_drv_res->mhi_evid_limits[0] = mhi_evid_limits[0];
5836 ipa_drv_res->mhi_evid_limits[1] = mhi_evid_limits[1];
5837 IPADBG(": mhi-event-ring-id-limits start=%u end=%u\n",
5838 mhi_evid_limits[0], mhi_evid_limits[1]);
5839 } else {
5840 if (elem_num > 0) {
5841 IPAERR("Invalid mhi event ring id limits number %d\n",
5842 elem_num);
5843 return -EINVAL;
5844 }
5845 IPADBG("use default mhi evt ring id limits start=%u end=%u\n",
5846 ipa_drv_res->mhi_evid_limits[0],
5847 ipa_drv_res->mhi_evid_limits[1]);
5848 }
5849
5850 elem_num = of_property_count_elems_of_size(pdev->dev.of_node,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005851 "qcom,ipa-tz-unlock-reg", sizeof(u32));
5852
5853 if (elem_num > 0 && elem_num % 2 == 0) {
5854 ipa_drv_res->ipa_tz_unlock_reg_num = elem_num / 2;
5855
5856 ipa_tz_unlock_reg = kcalloc(elem_num, sizeof(u32), GFP_KERNEL);
5857 if (ipa_tz_unlock_reg == NULL)
5858 return -ENOMEM;
5859
5860 ipa_drv_res->ipa_tz_unlock_reg = kcalloc(
5861 ipa_drv_res->ipa_tz_unlock_reg_num,
5862 sizeof(*ipa_drv_res->ipa_tz_unlock_reg),
5863 GFP_KERNEL);
5864 if (ipa_drv_res->ipa_tz_unlock_reg == NULL) {
5865 kfree(ipa_tz_unlock_reg);
5866 return -ENOMEM;
5867 }
5868
5869 if (of_property_read_u32_array(pdev->dev.of_node,
5870 "qcom,ipa-tz-unlock-reg", ipa_tz_unlock_reg,
5871 elem_num)) {
5872 IPAERR("failed to read register addresses\n");
5873 kfree(ipa_tz_unlock_reg);
5874 kfree(ipa_drv_res->ipa_tz_unlock_reg);
5875 return -EFAULT;
5876 }
5877
5878 pos = 0;
5879 for (i = 0; i < ipa_drv_res->ipa_tz_unlock_reg_num; i++) {
5880 ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr =
5881 ipa_tz_unlock_reg[pos++];
5882 ipa_drv_res->ipa_tz_unlock_reg[i].size =
5883 ipa_tz_unlock_reg[pos++];
Skylar Chang48afa052017-10-25 09:32:57 -07005884 IPADBG("tz unlock reg %d: addr 0x%pa size %llu\n", i,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005885 &ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr,
5886 ipa_drv_res->ipa_tz_unlock_reg[i].size);
5887 }
5888 kfree(ipa_tz_unlock_reg);
5889 }
Michael Adisumarta3e350812017-09-18 14:54:36 -07005890
5891 /* get IPA PM related information */
5892 result = get_ipa_dts_pm_info(pdev, ipa_drv_res);
5893 if (result) {
5894 IPAERR("failed to get pm info from dts %d\n", result);
5895 return result;
5896 }
5897
Amir Levy9659e592016-10-27 18:08:27 +03005898 return 0;
5899}
5900
5901static int ipa_smmu_wlan_cb_probe(struct device *dev)
5902{
Skylar Changefc0a0f2018-03-29 11:17:40 -07005903 struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_WLAN);
Amir Levy9659e592016-10-27 18:08:27 +03005904 int atomic_ctx = 1;
5905 int fast = 1;
5906 int bypass = 1;
5907 int ret;
5908 u32 add_map_size;
5909 const u32 *add_map;
5910 int i;
5911
5912 IPADBG("sub pdev=%p\n", dev);
5913
Skylar Changefc0a0f2018-03-29 11:17:40 -07005914 if (!smmu_info.present[IPA_SMMU_CB_WLAN]) {
5915 IPAERR("WLAN SMMU is disabled\n");
5916 return 0;
5917 }
5918
Amir Levy9659e592016-10-27 18:08:27 +03005919 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02005920 cb->iommu = iommu_domain_alloc(dev->bus);
Amir Levy9659e592016-10-27 18:08:27 +03005921 if (!cb->iommu) {
5922 IPAERR("could not alloc iommu domain\n");
5923 /* assume this failure is because iommu driver is not ready */
5924 return -EPROBE_DEFER;
5925 }
5926 cb->valid = true;
5927
Skylar Changefc0a0f2018-03-29 11:17:40 -07005928 if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass") ||
5929 ipa3_ctx->ipa_config_is_mhi) {
Michael Adisumarta93e97522017-10-06 15:49:46 -07005930 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = true;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005931 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN] = true;
5932
Amir Levy9659e592016-10-27 18:08:27 +03005933 if (iommu_domain_set_attr(cb->iommu,
5934 DOMAIN_ATTR_S1_BYPASS,
5935 &bypass)) {
5936 IPAERR("couldn't set bypass\n");
5937 cb->valid = false;
5938 return -EIO;
5939 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07005940 IPADBG("WLAN SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03005941 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07005942 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = false;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005943 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN] = false;
5944
Amir Levy9659e592016-10-27 18:08:27 +03005945 if (iommu_domain_set_attr(cb->iommu,
5946 DOMAIN_ATTR_ATOMIC,
5947 &atomic_ctx)) {
5948 IPAERR("couldn't disable coherent HTW\n");
5949 cb->valid = false;
5950 return -EIO;
5951 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07005952 IPADBG(" WLAN SMMU ATTR ATOMIC\n");
Amir Levy9659e592016-10-27 18:08:27 +03005953
5954 if (smmu_info.fast_map) {
5955 if (iommu_domain_set_attr(cb->iommu,
5956 DOMAIN_ATTR_FAST,
5957 &fast)) {
5958 IPAERR("couldn't set fast map\n");
5959 cb->valid = false;
5960 return -EIO;
5961 }
5962 IPADBG("SMMU fast map set\n");
5963 }
5964 }
5965
Michael Adisumarta93e97522017-10-06 15:49:46 -07005966 pr_info("IPA smmu_info.s1_bypass_arr[WLAN]=%d smmu_info.fast_map=%d\n",
5967 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN], smmu_info.fast_map);
5968
Amir Levy9659e592016-10-27 18:08:27 +03005969 ret = iommu_attach_device(cb->iommu, dev);
5970 if (ret) {
5971 IPAERR("could not attach device ret=%d\n", ret);
5972 cb->valid = false;
5973 return ret;
5974 }
5975 /* MAP ipa-uc ram */
5976 add_map = of_get_property(dev->of_node,
5977 "qcom,additional-mapping", &add_map_size);
5978 if (add_map) {
5979 /* mapping size is an array of 3-tuple of u32 */
5980 if (add_map_size % (3 * sizeof(u32))) {
5981 IPAERR("wrong additional mapping format\n");
5982 cb->valid = false;
5983 return -EFAULT;
5984 }
5985
5986 /* iterate of each entry of the additional mapping array */
5987 for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
5988 u32 iova = be32_to_cpu(add_map[i]);
5989 u32 pa = be32_to_cpu(add_map[i + 1]);
5990 u32 size = be32_to_cpu(add_map[i + 2]);
5991 unsigned long iova_p;
5992 phys_addr_t pa_p;
5993 u32 size_p;
5994
5995 IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
5996 iova_p, pa_p, size_p);
5997 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
5998 iova_p, &pa_p, size_p);
5999 ipa3_iommu_map(cb->iommu,
6000 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02006001 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03006002 }
6003 }
6004 return 0;
6005}
6006
6007static int ipa_smmu_uc_cb_probe(struct device *dev)
6008{
Skylar Changefc0a0f2018-03-29 11:17:40 -07006009 struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC);
Amir Levy9659e592016-10-27 18:08:27 +03006010 int atomic_ctx = 1;
6011 int bypass = 1;
6012 int fast = 1;
6013 int ret;
6014 u32 iova_ap_mapping[2];
6015
6016 IPADBG("UC CB PROBE sub pdev=%p\n", dev);
6017
Skylar Changefc0a0f2018-03-29 11:17:40 -07006018 if (!smmu_info.present[IPA_SMMU_CB_UC]) {
6019 IPAERR("UC SMMU is disabled\n");
6020 return 0;
6021 }
6022
Amir Levy9659e592016-10-27 18:08:27 +03006023 ret = of_property_read_u32_array(dev->of_node, "qcom,iova-mapping",
6024 iova_ap_mapping, 2);
6025 if (ret) {
6026 IPAERR("Fail to read UC start/size iova addresses\n");
6027 return ret;
6028 }
6029 cb->va_start = iova_ap_mapping[0];
6030 cb->va_size = iova_ap_mapping[1];
6031 cb->va_end = cb->va_start + cb->va_size;
6032 IPADBG("UC va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
6033
6034 if (smmu_info.use_64_bit_dma_mask) {
6035 if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
6036 dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
6037 IPAERR("DMA set 64bit mask failed\n");
6038 return -EOPNOTSUPP;
6039 }
6040 } else {
6041 if (dma_set_mask(dev, DMA_BIT_MASK(32)) ||
6042 dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
6043 IPAERR("DMA set 32bit mask failed\n");
6044 return -EOPNOTSUPP;
6045 }
6046 }
6047 IPADBG("UC CB PROBE=%p create IOMMU mapping\n", dev);
6048
6049 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02006050 cb->mapping = arm_iommu_create_mapping(dev->bus,
Amir Levy9659e592016-10-27 18:08:27 +03006051 cb->va_start, cb->va_size);
6052 if (IS_ERR_OR_NULL(cb->mapping)) {
6053 IPADBG("Fail to create mapping\n");
6054 /* assume this failure is because iommu driver is not ready */
6055 return -EPROBE_DEFER;
6056 }
6057 IPADBG("SMMU mapping created\n");
6058 cb->valid = true;
6059
Amir Levy9659e592016-10-27 18:08:27 +03006060 IPADBG("UC CB PROBE sub pdev=%p set attribute\n", dev);
Michael Adisumarta93e97522017-10-06 15:49:46 -07006061
Skylar Changefc0a0f2018-03-29 11:17:40 -07006062 if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass") ||
6063 ipa3_ctx->ipa_config_is_mhi) {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006064 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC] = true;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07006065 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = true;
6066
Amir Levy9659e592016-10-27 18:08:27 +03006067 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07006068 DOMAIN_ATTR_S1_BYPASS,
6069 &bypass)) {
Amir Levy9659e592016-10-27 18:08:27 +03006070 IPAERR("couldn't set bypass\n");
6071 arm_iommu_release_mapping(cb->mapping);
6072 cb->valid = false;
6073 return -EIO;
6074 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006075 IPADBG("UC SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03006076 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006077 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC] = false;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07006078 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = false;
6079
Amir Levy9659e592016-10-27 18:08:27 +03006080 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07006081 DOMAIN_ATTR_ATOMIC,
6082 &atomic_ctx)) {
Amir Levy9659e592016-10-27 18:08:27 +03006083 IPAERR("couldn't set domain as atomic\n");
6084 arm_iommu_release_mapping(cb->mapping);
6085 cb->valid = false;
6086 return -EIO;
6087 }
6088 IPADBG("SMMU atomic set\n");
6089
6090 if (smmu_info.fast_map) {
6091 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07006092 DOMAIN_ATTR_FAST,
6093 &fast)) {
Amir Levy9659e592016-10-27 18:08:27 +03006094 IPAERR("couldn't set fast map\n");
6095 arm_iommu_release_mapping(cb->mapping);
6096 cb->valid = false;
6097 return -EIO;
6098 }
6099 IPADBG("SMMU fast map set\n");
6100 }
6101 }
6102
Michael Adisumarta93e97522017-10-06 15:49:46 -07006103 pr_info("IPA smmu_info.s1_bypass_arr[UC]=%d smmu_info.fast_map=%d\n",
6104 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC], smmu_info.fast_map);
6105
Amir Levy9659e592016-10-27 18:08:27 +03006106 IPADBG("UC CB PROBE sub pdev=%p attaching IOMMU device\n", dev);
6107 ret = arm_iommu_attach_device(cb->dev, cb->mapping);
6108 if (ret) {
6109 IPAERR("could not attach device ret=%d\n", ret);
6110 arm_iommu_release_mapping(cb->mapping);
6111 cb->valid = false;
6112 return ret;
6113 }
6114
6115 cb->next_addr = cb->va_end;
6116 ipa3_ctx->uc_pdev = dev;
6117
6118 return 0;
6119}
6120
6121static int ipa_smmu_ap_cb_probe(struct device *dev)
6122{
Skylar Changefc0a0f2018-03-29 11:17:40 -07006123 struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
Amir Levy9659e592016-10-27 18:08:27 +03006124 int result;
Amir Levy9659e592016-10-27 18:08:27 +03006125 int atomic_ctx = 1;
6126 int fast = 1;
6127 int bypass = 1;
6128 u32 iova_ap_mapping[2];
6129 u32 add_map_size;
Mohammed Javid36d13cf2018-01-26 22:49:03 +05306130 u32 q6_smem_size;
Amir Levy9659e592016-10-27 18:08:27 +03006131 const u32 *add_map;
6132 void *smem_addr;
6133 int i;
6134
6135 IPADBG("AP CB probe: sub pdev=%p\n", dev);
6136
Skylar Changefc0a0f2018-03-29 11:17:40 -07006137 if (!smmu_info.present[IPA_SMMU_CB_AP]) {
6138 IPAERR("AP SMMU is disabled");
6139 return 0;
6140 }
6141
Amir Levy9659e592016-10-27 18:08:27 +03006142 result = of_property_read_u32_array(dev->of_node, "qcom,iova-mapping",
6143 iova_ap_mapping, 2);
6144 if (result) {
6145 IPAERR("Fail to read AP start/size iova addresses\n");
6146 return result;
6147 }
6148 cb->va_start = iova_ap_mapping[0];
6149 cb->va_size = iova_ap_mapping[1];
6150 cb->va_end = cb->va_start + cb->va_size;
6151 IPADBG("AP va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
6152
6153 if (smmu_info.use_64_bit_dma_mask) {
6154 if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
6155 dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
6156 IPAERR("DMA set 64bit mask failed\n");
6157 return -EOPNOTSUPP;
6158 }
6159 } else {
6160 if (dma_set_mask(dev, DMA_BIT_MASK(32)) ||
6161 dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
6162 IPAERR("DMA set 32bit mask failed\n");
6163 return -EOPNOTSUPP;
6164 }
6165 }
6166
6167 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02006168 cb->mapping = arm_iommu_create_mapping(dev->bus,
Amir Levy9659e592016-10-27 18:08:27 +03006169 cb->va_start, cb->va_size);
6170 if (IS_ERR_OR_NULL(cb->mapping)) {
6171 IPADBG("Fail to create mapping\n");
6172 /* assume this failure is because iommu driver is not ready */
6173 return -EPROBE_DEFER;
6174 }
6175 IPADBG("SMMU mapping created\n");
6176 cb->valid = true;
6177
Michael Adisumarta93e97522017-10-06 15:49:46 -07006178 if (of_property_read_bool(dev->of_node,
Skylar Changefc0a0f2018-03-29 11:17:40 -07006179 "qcom,smmu-s1-bypass") || ipa3_ctx->ipa_config_is_mhi) {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006180 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP] = true;
Skylar Change87894f2018-04-02 15:49:12 -07006181 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] = true;
Amir Levy9659e592016-10-27 18:08:27 +03006182 if (iommu_domain_set_attr(cb->mapping->domain,
6183 DOMAIN_ATTR_S1_BYPASS,
6184 &bypass)) {
6185 IPAERR("couldn't set bypass\n");
6186 arm_iommu_release_mapping(cb->mapping);
6187 cb->valid = false;
6188 return -EIO;
6189 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006190 IPADBG("AP/USB SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03006191 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006192 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP] = false;
Skylar Change87894f2018-04-02 15:49:12 -07006193 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] = false;
Amir Levy9659e592016-10-27 18:08:27 +03006194 if (iommu_domain_set_attr(cb->mapping->domain,
6195 DOMAIN_ATTR_ATOMIC,
6196 &atomic_ctx)) {
6197 IPAERR("couldn't set domain as atomic\n");
6198 arm_iommu_release_mapping(cb->mapping);
6199 cb->valid = false;
6200 return -EIO;
6201 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006202 IPADBG("AP/USB SMMU atomic set\n");
Amir Levy9659e592016-10-27 18:08:27 +03006203
6204 if (iommu_domain_set_attr(cb->mapping->domain,
6205 DOMAIN_ATTR_FAST,
6206 &fast)) {
6207 IPAERR("couldn't set fast map\n");
6208 arm_iommu_release_mapping(cb->mapping);
6209 cb->valid = false;
6210 return -EIO;
6211 }
6212 IPADBG("SMMU fast map set\n");
6213 }
6214
Michael Adisumarta93e97522017-10-06 15:49:46 -07006215 pr_info("IPA smmu_info.s1_bypass_arr[AP]=%d smmu_info.fast_map=%d\n",
6216 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP], smmu_info.fast_map);
6217
Amir Levy9659e592016-10-27 18:08:27 +03006218 result = arm_iommu_attach_device(cb->dev, cb->mapping);
6219 if (result) {
6220 IPAERR("couldn't attach to IOMMU ret=%d\n", result);
6221 cb->valid = false;
6222 return result;
6223 }
6224
6225 add_map = of_get_property(dev->of_node,
6226 "qcom,additional-mapping", &add_map_size);
6227 if (add_map) {
6228 /* mapping size is an array of 3-tuple of u32 */
6229 if (add_map_size % (3 * sizeof(u32))) {
6230 IPAERR("wrong additional mapping format\n");
6231 cb->valid = false;
6232 return -EFAULT;
6233 }
6234
6235 /* iterate of each entry of the additional mapping array */
6236 for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
6237 u32 iova = be32_to_cpu(add_map[i]);
6238 u32 pa = be32_to_cpu(add_map[i + 1]);
6239 u32 size = be32_to_cpu(add_map[i + 2]);
6240 unsigned long iova_p;
6241 phys_addr_t pa_p;
6242 u32 size_p;
6243
6244 IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
6245 iova_p, pa_p, size_p);
6246 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
6247 iova_p, &pa_p, size_p);
6248 ipa3_iommu_map(cb->mapping->domain,
6249 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02006250 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03006251 }
6252 }
6253
Mohammed Javid36d13cf2018-01-26 22:49:03 +05306254 result = of_property_read_u32_array(dev->of_node,
6255 "qcom,ipa-q6-smem-size", &q6_smem_size, 1);
6256 if (result) {
6257 IPADBG("ipa q6 smem size = %d\n", IPA_SMEM_SIZE);
6258 /* map SMEM memory for IPA table accesses */
6259 smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
6260 SMEM_MODEM, 0);
6261 } else {
6262 IPADBG("ipa q6 smem size = %d\n", q6_smem_size);
6263 smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, q6_smem_size,
6264 SMEM_MODEM, 0);
6265 }
Amir Levy9659e592016-10-27 18:08:27 +03006266 if (smem_addr) {
6267 phys_addr_t iova = smem_virt_to_phys(smem_addr);
6268 phys_addr_t pa = iova;
6269 unsigned long iova_p;
6270 phys_addr_t pa_p;
6271 u32 size_p;
6272
6273 IPA_SMMU_ROUND_TO_PAGE(iova, pa, IPA_SMEM_SIZE,
6274 iova_p, pa_p, size_p);
6275 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
6276 iova_p, &pa_p, size_p);
6277 ipa3_iommu_map(cb->mapping->domain,
6278 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02006279 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03006280 }
6281
6282
Skylar Changefc0a0f2018-03-29 11:17:40 -07006283 smmu_info.present[IPA_SMMU_CB_AP] = true;
6284 ipa3_ctx->pdev = dev;
Amir Levy9659e592016-10-27 18:08:27 +03006285
Michael Adisumartac8c404a2018-04-05 18:01:45 -07006286 return 0;
Amir Levy9659e592016-10-27 18:08:27 +03006287}
6288
Skylar Changefc0a0f2018-03-29 11:17:40 -07006289static int ipa_smmu_cb_probe(struct device *dev, enum ipa_smmu_cb_type cb_type)
6290{
6291 switch (cb_type) {
6292 case IPA_SMMU_CB_AP:
6293 return ipa_smmu_ap_cb_probe(dev);
6294 case IPA_SMMU_CB_WLAN:
6295 return ipa_smmu_wlan_cb_probe(dev);
6296 case IPA_SMMU_CB_UC:
6297 return ipa_smmu_uc_cb_probe(dev);
6298 case IPA_SMMU_CB_MAX:
6299 IPAERR("Invalid cb_type\n");
6300 }
6301 return 0;
6302}
6303
6304static int ipa3_attach_to_smmu(void)
6305{
6306 struct ipa_smmu_cb_ctx *cb;
6307 int i, result;
6308
6309 ipa3_ctx->pdev = &ipa3_ctx->master_pdev->dev;
6310 ipa3_ctx->uc_pdev = &ipa3_ctx->master_pdev->dev;
6311
6312 if (smmu_info.arm_smmu) {
6313 IPADBG("smmu is enabled\n");
6314 for (i = 0; i < IPA_SMMU_CB_MAX; i++) {
6315 cb = ipa3_get_smmu_ctx(i);
6316 result = ipa_smmu_cb_probe(cb->dev, i);
6317 if (result)
6318 IPAERR("probe failed for cb %d\n", i);
6319 }
6320 } else {
6321 IPADBG("smmu is disabled\n");
6322 }
6323 return 0;
6324}
6325
Amir Levy9659e592016-10-27 18:08:27 +03006326static irqreturn_t ipa3_smp2p_modem_clk_query_isr(int irq, void *ctxt)
6327{
6328 ipa3_freeze_clock_vote_and_notify_modem();
6329
6330 return IRQ_HANDLED;
6331}
6332
6333static int ipa3_smp2p_probe(struct device *dev)
6334{
6335 struct device_node *node = dev->of_node;
6336 int res;
6337
Mohammed Javid7de12702017-07-21 15:22:58 +05306338 if (ipa3_ctx == NULL) {
6339 IPAERR("ipa3_ctx was not initialized\n");
6340 return -ENXIO;
6341 }
Amir Levy9659e592016-10-27 18:08:27 +03006342 IPADBG("node->name=%s\n", node->name);
6343 if (strcmp("qcom,smp2pgpio_map_ipa_1_out", node->name) == 0) {
6344 res = of_get_gpio(node, 0);
6345 if (res < 0) {
6346 IPADBG("of_get_gpio returned %d\n", res);
6347 return res;
6348 }
6349
6350 ipa3_ctx->smp2p_info.out_base_id = res;
6351 IPADBG("smp2p out_base_id=%d\n",
6352 ipa3_ctx->smp2p_info.out_base_id);
6353 } else if (strcmp("qcom,smp2pgpio_map_ipa_1_in", node->name) == 0) {
6354 int irq;
6355
6356 res = of_get_gpio(node, 0);
6357 if (res < 0) {
6358 IPADBG("of_get_gpio returned %d\n", res);
6359 return res;
6360 }
6361
6362 ipa3_ctx->smp2p_info.in_base_id = res;
6363 IPADBG("smp2p in_base_id=%d\n",
6364 ipa3_ctx->smp2p_info.in_base_id);
6365
6366 /* register for modem clk query */
6367 irq = gpio_to_irq(ipa3_ctx->smp2p_info.in_base_id +
6368 IPA_GPIO_IN_QUERY_CLK_IDX);
6369 if (irq < 0) {
6370 IPAERR("gpio_to_irq failed %d\n", irq);
6371 return -ENODEV;
6372 }
6373 IPADBG("smp2p irq#=%d\n", irq);
6374 res = request_irq(irq,
6375 (irq_handler_t)ipa3_smp2p_modem_clk_query_isr,
6376 IRQF_TRIGGER_RISING, "ipa_smp2p_clk_vote", dev);
6377 if (res) {
6378 IPAERR("fail to register smp2p irq=%d\n", irq);
6379 return -ENODEV;
6380 }
6381 res = enable_irq_wake(ipa3_ctx->smp2p_info.in_base_id +
6382 IPA_GPIO_IN_QUERY_CLK_IDX);
6383 if (res)
6384 IPAERR("failed to enable irq wake\n");
6385 }
6386
6387 return 0;
6388}
6389
6390int ipa3_plat_drv_probe(struct platform_device *pdev_p,
6391 struct ipa_api_controller *api_ctrl,
6392 const struct of_device_id *pdrv_match)
6393{
6394 int result;
6395 struct device *dev = &pdev_p->dev;
Skylar Changefc0a0f2018-03-29 11:17:40 -07006396 struct ipa_smmu_cb_ctx *cb;
Amir Levy9659e592016-10-27 18:08:27 +03006397
6398 IPADBG("IPA driver probing started\n");
6399 IPADBG("dev->of_node->name = %s\n", dev->of_node->name);
6400
Skylar Changefc0a0f2018-03-29 11:17:40 -07006401 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-ap-cb")) {
6402 cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
6403 cb->dev = dev;
6404 smmu_info.present[IPA_SMMU_CB_AP] = true;
Amir Levy9659e592016-10-27 18:08:27 +03006405
Skylar Changefc0a0f2018-03-29 11:17:40 -07006406 return 0;
6407 }
Amir Levy9659e592016-10-27 18:08:27 +03006408
Skylar Changefc0a0f2018-03-29 11:17:40 -07006409 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-wlan-cb")) {
6410 cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_WLAN);
6411 cb->dev = dev;
6412 smmu_info.present[IPA_SMMU_CB_WLAN] = true;
6413
6414 return 0;
6415 }
6416
6417 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-uc-cb")) {
6418 cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC);
6419 cb->dev = dev;
6420 smmu_info.present[IPA_SMMU_CB_UC] = true;
6421
6422 return 0;
6423 }
Amir Levy9659e592016-10-27 18:08:27 +03006424
6425 if (of_device_is_compatible(dev->of_node,
6426 "qcom,smp2pgpio-map-ipa-1-in"))
6427 return ipa3_smp2p_probe(dev);
6428
6429 if (of_device_is_compatible(dev->of_node,
6430 "qcom,smp2pgpio-map-ipa-1-out"))
6431 return ipa3_smp2p_probe(dev);
6432
Amir Levy9659e592016-10-27 18:08:27 +03006433 result = get_ipa_dts_configuration(pdev_p, &ipa3_res);
6434 if (result) {
6435 IPAERR("IPA dts parsing failed\n");
6436 return result;
6437 }
6438
6439 result = ipa3_bind_api_controller(ipa3_res.ipa_hw_type, api_ctrl);
6440 if (result) {
6441 IPAERR("IPA API binding failed\n");
6442 return result;
6443 }
6444
Amir Levy9659e592016-10-27 18:08:27 +03006445 if (of_property_read_bool(pdev_p->dev.of_node, "qcom,arm-smmu")) {
6446 if (of_property_read_bool(pdev_p->dev.of_node,
Amir Levy9659e592016-10-27 18:08:27 +03006447 "qcom,smmu-fast-map"))
6448 smmu_info.fast_map = true;
6449 if (of_property_read_bool(pdev_p->dev.of_node,
6450 "qcom,use-64-bit-dma-mask"))
6451 smmu_info.use_64_bit_dma_mask = true;
6452 smmu_info.arm_smmu = true;
Amir Levy9659e592016-10-27 18:08:27 +03006453 } else if (of_property_read_bool(pdev_p->dev.of_node,
6454 "qcom,msm-smmu")) {
6455 IPAERR("Legacy IOMMU not supported\n");
6456 result = -EOPNOTSUPP;
6457 } else {
6458 if (of_property_read_bool(pdev_p->dev.of_node,
6459 "qcom,use-64-bit-dma-mask")) {
6460 if (dma_set_mask(&pdev_p->dev, DMA_BIT_MASK(64)) ||
6461 dma_set_coherent_mask(&pdev_p->dev,
6462 DMA_BIT_MASK(64))) {
6463 IPAERR("DMA set 64bit mask failed\n");
6464 return -EOPNOTSUPP;
6465 }
6466 } else {
6467 if (dma_set_mask(&pdev_p->dev, DMA_BIT_MASK(32)) ||
6468 dma_set_coherent_mask(&pdev_p->dev,
6469 DMA_BIT_MASK(32))) {
6470 IPAERR("DMA set 32bit mask failed\n");
6471 return -EOPNOTSUPP;
6472 }
6473 }
Skylar Changefc0a0f2018-03-29 11:17:40 -07006474 }
Amir Levy9659e592016-10-27 18:08:27 +03006475
Skylar Changefc0a0f2018-03-29 11:17:40 -07006476 /* Proceed to real initialization */
6477 result = ipa3_pre_init(&ipa3_res, pdev_p);
6478 if (result) {
6479 IPAERR("ipa3_init failed\n");
6480 return result;
Amir Levy9659e592016-10-27 18:08:27 +03006481 }
6482
Ghanim Fodi115bf8a2017-04-21 01:36:06 -07006483 result = of_platform_populate(pdev_p->dev.of_node,
6484 pdrv_match, NULL, &pdev_p->dev);
6485 if (result) {
6486 IPAERR("failed to populate platform\n");
6487 return result;
6488 }
6489
Amir Levy9659e592016-10-27 18:08:27 +03006490 return result;
6491}
6492
6493/**
6494 * ipa3_ap_suspend() - suspend callback for runtime_pm
6495 * @dev: pointer to device
6496 *
6497 * This callback will be invoked by the runtime_pm framework when an AP suspend
6498 * operation is invoked, usually by pressing a suspend button.
6499 *
6500 * Returns -EAGAIN to runtime_pm framework in case IPA is in use by AP.
6501 * This will postpone the suspend operation until IPA is no longer used by AP.
Skylar Chang68c37d82018-04-07 16:42:36 -07006502 */
Amir Levy9659e592016-10-27 18:08:27 +03006503int ipa3_ap_suspend(struct device *dev)
6504{
6505 int i;
6506
6507 IPADBG("Enter...\n");
6508
6509 /* In case there is a tx/rx handler in polling mode fail to suspend */
6510 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
6511 if (ipa3_ctx->ep[i].sys &&
6512 atomic_read(&ipa3_ctx->ep[i].sys->curr_polling_state)) {
6513 IPAERR("EP %d is in polling state, do not suspend\n",
6514 i);
6515 return -EAGAIN;
6516 }
6517 }
6518
Michael Adisumarta3e350812017-09-18 14:54:36 -07006519 if (ipa3_ctx->use_ipa_pm) {
6520 ipa_pm_deactivate_all_deferred();
6521 } else {
6522 /*
6523 * Release transport IPA resource without waiting
6524 * for inactivity timer
6525 */
6526 atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
6527 ipa3_transport_release_resource(NULL);
6528 }
Amir Levy9659e592016-10-27 18:08:27 +03006529 IPADBG("Exit\n");
6530
6531 return 0;
6532}
6533
6534/**
Skylar Chang68c37d82018-04-07 16:42:36 -07006535 * ipa3_ap_resume() - resume callback for runtime_pm
6536 * @dev: pointer to device
6537 *
6538 * This callback will be invoked by the runtime_pm framework when an AP resume
6539 * operation is invoked.
6540 *
6541 * Always returns 0 since resume should always succeed.
6542 */
Amir Levy9659e592016-10-27 18:08:27 +03006543int ipa3_ap_resume(struct device *dev)
6544{
6545 return 0;
6546}
6547
6548struct ipa3_context *ipa3_get_ctx(void)
6549{
6550 return ipa3_ctx;
6551}
6552
Amir Levy9659e592016-10-27 18:08:27 +03006553static void ipa_gsi_notify_cb(struct gsi_per_notify *notify)
6554{
6555 switch (notify->evt_id) {
6556 case GSI_PER_EVT_GLOB_ERROR:
6557 IPAERR("Got GSI_PER_EVT_GLOB_ERROR\n");
6558 IPAERR("Err_desc = 0x%04x\n", notify->data.err_desc);
6559 break;
6560 case GSI_PER_EVT_GLOB_GP1:
6561 IPAERR("Got GSI_PER_EVT_GLOB_GP1\n");
6562 BUG();
6563 break;
6564 case GSI_PER_EVT_GLOB_GP2:
6565 IPAERR("Got GSI_PER_EVT_GLOB_GP2\n");
6566 BUG();
6567 break;
6568 case GSI_PER_EVT_GLOB_GP3:
6569 IPAERR("Got GSI_PER_EVT_GLOB_GP3\n");
6570 BUG();
6571 break;
6572 case GSI_PER_EVT_GENERAL_BREAK_POINT:
6573 IPAERR("Got GSI_PER_EVT_GENERAL_BREAK_POINT\n");
6574 break;
6575 case GSI_PER_EVT_GENERAL_BUS_ERROR:
6576 IPAERR("Got GSI_PER_EVT_GENERAL_BUS_ERROR\n");
6577 BUG();
6578 break;
6579 case GSI_PER_EVT_GENERAL_CMD_FIFO_OVERFLOW:
6580 IPAERR("Got GSI_PER_EVT_GENERAL_CMD_FIFO_OVERFLOW\n");
6581 BUG();
6582 break;
6583 case GSI_PER_EVT_GENERAL_MCS_STACK_OVERFLOW:
6584 IPAERR("Got GSI_PER_EVT_GENERAL_MCS_STACK_OVERFLOW\n");
6585 BUG();
6586 break;
6587 default:
6588 IPAERR("Received unexpected evt: %d\n",
6589 notify->evt_id);
6590 BUG();
6591 }
6592}
6593
6594int ipa3_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data)
6595{
6596 struct ipa3_ready_cb_info *cb_info = NULL;
6597
6598 /* check ipa3_ctx existed or not */
6599 if (!ipa3_ctx) {
6600 IPADBG("IPA driver haven't initialized\n");
6601 return -ENXIO;
6602 }
6603 mutex_lock(&ipa3_ctx->lock);
6604 if (ipa3_ctx->ipa_initialization_complete) {
6605 mutex_unlock(&ipa3_ctx->lock);
6606 IPADBG("IPA driver finished initialization already\n");
6607 return -EEXIST;
6608 }
6609
6610 cb_info = kmalloc(sizeof(struct ipa3_ready_cb_info), GFP_KERNEL);
6611 if (!cb_info) {
6612 mutex_unlock(&ipa3_ctx->lock);
6613 return -ENOMEM;
6614 }
6615
6616 cb_info->ready_cb = ipa_ready_cb;
6617 cb_info->user_data = user_data;
6618
6619 list_add_tail(&cb_info->link, &ipa3_ctx->ipa_ready_cb_list);
6620 mutex_unlock(&ipa3_ctx->lock);
6621
6622 return 0;
6623}
6624
6625int ipa3_iommu_map(struct iommu_domain *domain,
6626 unsigned long iova, phys_addr_t paddr, size_t size, int prot)
6627{
Skylar Changefc0a0f2018-03-29 11:17:40 -07006628 struct ipa_smmu_cb_ctx *ap_cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
6629 struct ipa_smmu_cb_ctx *uc_cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC);
Amir Levy9659e592016-10-27 18:08:27 +03006630
6631 IPADBG("domain =0x%p iova 0x%lx\n", domain, iova);
6632 IPADBG("paddr =0x%pa size 0x%x\n", &paddr, (u32)size);
6633
6634 /* make sure no overlapping */
6635 if (domain == ipa3_get_smmu_domain()) {
6636 if (iova >= ap_cb->va_start && iova < ap_cb->va_end) {
6637 IPAERR("iommu AP overlap addr 0x%lx\n", iova);
6638 ipa_assert();
6639 return -EFAULT;
6640 }
6641 } else if (domain == ipa3_get_wlan_smmu_domain()) {
6642 /* wlan is one time map */
6643 } else if (domain == ipa3_get_uc_smmu_domain()) {
6644 if (iova >= uc_cb->va_start && iova < uc_cb->va_end) {
6645 IPAERR("iommu uC overlap addr 0x%lx\n", iova);
6646 ipa_assert();
6647 return -EFAULT;
6648 }
6649 } else {
6650 IPAERR("Unexpected domain 0x%p\n", domain);
6651 ipa_assert();
6652 return -EFAULT;
6653 }
6654
6655 return iommu_map(domain, iova, paddr, size, prot);
6656}
6657
Michael Adisumartad04e6d62017-11-09 17:46:35 -08006658/**
6659 * ipa3_get_smmu_params()- Return the ipa3 smmu related params.
6660 */
6661int ipa3_get_smmu_params(struct ipa_smmu_in_params *in,
6662 struct ipa_smmu_out_params *out)
6663{
6664 bool is_smmu_enable = 0;
6665
6666 if (out == NULL || in == NULL) {
6667 IPAERR("bad parms for Client SMMU out params\n");
6668 return -EINVAL;
6669 }
6670
6671 if (!ipa3_ctx) {
6672 IPAERR("IPA not yet initialized\n");
6673 return -EINVAL;
6674 }
6675
6676 switch (in->smmu_client) {
6677 case IPA_SMMU_WLAN_CLIENT:
6678 is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] |
6679 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN]);
6680 break;
6681 default:
6682 is_smmu_enable = 0;
6683 IPAERR("Trying to get illegal clients SMMU status");
6684 return -EINVAL;
6685 }
6686
6687 out->smmu_enable = is_smmu_enable;
6688
6689 return 0;
6690}
6691
Amir Levy9659e592016-10-27 18:08:27 +03006692MODULE_LICENSE("GPL v2");
6693MODULE_DESCRIPTION("IPA HW device driver");