blob: 09d2ca0fd34e41b3f23093746eb0c5aef78c1ee1 [file] [log] [blame]
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02001/* Copyright (c) 2012-2017, 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
Ghanim Fodia5f376a2017-10-17 18:14:53 +0300272static void ipa3_load_ipa_fw(struct work_struct *work);
273static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw);
Utkarsh Saxenaded78142017-05-03 14:04:30 +0530274
Skylar Chang242952b2017-07-20 15:04:05 -0700275static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work);
276static DECLARE_WORK(ipa_dec_clients_disable_clks_on_wq_work,
277 ipa_dec_clients_disable_clks_on_wq);
278
Amir Levy9659e592016-10-27 18:08:27 +0300279static struct ipa3_plat_drv_res ipa3_res = {0, };
280struct msm_bus_scale_pdata *ipa3_bus_scale_table;
281
282static struct clk *ipa3_clk;
283
284struct ipa3_context *ipa3_ctx;
285static struct device *master_dev;
286struct platform_device *ipa3_pdev;
287static struct {
288 bool present;
289 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
371static int ipa3_active_clients_panic_notifier(struct notifier_block *this,
372 unsigned long event, void *ptr)
373{
Skylar Chang242952b2017-07-20 15:04:05 -0700374 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +0300375 ipa3_active_clients_log_print_table(active_clients_table_buf,
376 IPA3_ACTIVE_CLIENTS_TABLE_BUF_SIZE);
377 IPAERR("%s", active_clients_table_buf);
Skylar Chang242952b2017-07-20 15:04:05 -0700378 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +0300379
380 return NOTIFY_DONE;
381}
382
383static struct notifier_block ipa3_active_clients_panic_blk = {
384 .notifier_call = ipa3_active_clients_panic_notifier,
385};
386
387static int ipa3_active_clients_log_insert(const char *string)
388{
389 int head;
390 int tail;
391
392 if (!ipa3_ctx->ipa3_active_clients_logging.log_rdy)
393 return -EPERM;
394
395 head = ipa3_ctx->ipa3_active_clients_logging.log_head;
396 tail = ipa3_ctx->ipa3_active_clients_logging.log_tail;
397
398 memset(ipa3_ctx->ipa3_active_clients_logging.log_buffer[head], '_',
399 IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN);
400 strlcpy(ipa3_ctx->ipa3_active_clients_logging.log_buffer[head], string,
401 (size_t)IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN);
402 head = (head + 1) % IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES;
403 if (tail == head)
404 tail = (tail + 1) % IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES;
405
406 ipa3_ctx->ipa3_active_clients_logging.log_tail = tail;
407 ipa3_ctx->ipa3_active_clients_logging.log_head = head;
408
409 return 0;
410}
411
412static int ipa3_active_clients_log_init(void)
413{
414 int i;
415
Skylar Chang69ae50e2017-07-31 13:13:29 -0700416 spin_lock_init(&ipa3_ctx->ipa3_active_clients_logging.lock);
Amir Levy9659e592016-10-27 18:08:27 +0300417 ipa3_ctx->ipa3_active_clients_logging.log_buffer[0] = kzalloc(
418 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES *
419 sizeof(char[IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN]),
420 GFP_KERNEL);
421 active_clients_table_buf = kzalloc(sizeof(
422 char[IPA3_ACTIVE_CLIENTS_TABLE_BUF_SIZE]), GFP_KERNEL);
423 if (ipa3_ctx->ipa3_active_clients_logging.log_buffer == NULL) {
424 pr_err("Active Clients Logging memory allocation failed");
425 goto bail;
426 }
427 for (i = 0; i < IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; i++) {
428 ipa3_ctx->ipa3_active_clients_logging.log_buffer[i] =
429 ipa3_ctx->ipa3_active_clients_logging.log_buffer[0] +
430 (IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN * i);
431 }
432 ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
433 ipa3_ctx->ipa3_active_clients_logging.log_tail =
434 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
435 hash_init(ipa3_ctx->ipa3_active_clients_logging.htable);
436 atomic_notifier_chain_register(&panic_notifier_list,
437 &ipa3_active_clients_panic_blk);
438 ipa3_ctx->ipa3_active_clients_logging.log_rdy = 1;
439
440 return 0;
441
442bail:
443 return -ENOMEM;
444}
445
446void ipa3_active_clients_log_clear(void)
447{
Skylar Chang69ae50e2017-07-31 13:13:29 -0700448 unsigned long flags;
449
450 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300451 ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
452 ipa3_ctx->ipa3_active_clients_logging.log_tail =
453 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700454 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
455 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300456}
457
458static void ipa3_active_clients_log_destroy(void)
459{
Skylar Chang69ae50e2017-07-31 13:13:29 -0700460 unsigned long flags;
461
462 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
Amir Levy9659e592016-10-27 18:08:27 +0300463 ipa3_ctx->ipa3_active_clients_logging.log_rdy = 0;
464 kfree(ipa3_ctx->ipa3_active_clients_logging.log_buffer[0]);
465 ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
466 ipa3_ctx->ipa3_active_clients_logging.log_tail =
467 IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
Skylar Chang69ae50e2017-07-31 13:13:29 -0700468 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
469 flags);
Amir Levy9659e592016-10-27 18:08:27 +0300470}
471
Amir Levy9659e592016-10-27 18:08:27 +0300472static struct ipa_smmu_cb_ctx smmu_cb[IPA_SMMU_CB_MAX];
473
474struct iommu_domain *ipa3_get_smmu_domain(void)
475{
476 if (smmu_cb[IPA_SMMU_CB_AP].valid)
477 return smmu_cb[IPA_SMMU_CB_AP].mapping->domain;
478
479 IPAERR("CB not valid\n");
480
481 return NULL;
482}
483
484struct iommu_domain *ipa3_get_uc_smmu_domain(void)
485{
486 if (smmu_cb[IPA_SMMU_CB_UC].valid)
487 return smmu_cb[IPA_SMMU_CB_UC].mapping->domain;
488
489 IPAERR("CB not valid\n");
490
491 return NULL;
492}
493
494struct iommu_domain *ipa3_get_wlan_smmu_domain(void)
495{
496 if (smmu_cb[IPA_SMMU_CB_WLAN].valid)
497 return smmu_cb[IPA_SMMU_CB_WLAN].iommu;
498
499 IPAERR("CB not valid\n");
500
501 return NULL;
502}
503
504
505struct device *ipa3_get_dma_dev(void)
506{
507 return ipa3_ctx->pdev;
508}
509
510/**
511 * ipa3_get_smmu_ctx()- Return the wlan smmu context
512 *
513 * Return value: pointer to smmu context address
514 */
515struct ipa_smmu_cb_ctx *ipa3_get_smmu_ctx(void)
516{
517 return &smmu_cb[IPA_SMMU_CB_AP];
518}
519
520/**
521 * ipa3_get_wlan_smmu_ctx()- Return the wlan smmu context
522 *
523 * Return value: pointer to smmu context address
524 */
525struct ipa_smmu_cb_ctx *ipa3_get_wlan_smmu_ctx(void)
526{
527 return &smmu_cb[IPA_SMMU_CB_WLAN];
528}
529
530/**
531 * ipa3_get_uc_smmu_ctx()- Return the uc smmu context
532 *
533 * Return value: pointer to smmu context address
534 */
535struct ipa_smmu_cb_ctx *ipa3_get_uc_smmu_ctx(void)
536{
537 return &smmu_cb[IPA_SMMU_CB_UC];
538}
539
540static int ipa3_open(struct inode *inode, struct file *filp)
541{
542 struct ipa3_context *ctx = NULL;
543
544 IPADBG_LOW("ENTER\n");
545 ctx = container_of(inode->i_cdev, struct ipa3_context, cdev);
546 filp->private_data = ctx;
547
548 return 0;
549}
550
Amir Levy9659e592016-10-27 18:08:27 +0300551static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type)
552{
553 if (!buff) {
554 IPAERR("Null buffer\n");
555 return;
556 }
557
558 if (type != WAN_UPSTREAM_ROUTE_ADD &&
559 type != WAN_UPSTREAM_ROUTE_DEL &&
560 type != WAN_EMBMS_CONNECT) {
561 IPAERR("Wrong type given. buff %p type %d\n", buff, type);
562 return;
563 }
564
565 kfree(buff);
566}
567
Mohammed Javidb4b5ef42017-08-29 01:05:46 +0530568static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type, bool is_cache)
Amir Levy9659e592016-10-27 18:08:27 +0300569{
570 int retval;
571 struct ipa_wan_msg *wan_msg;
572 struct ipa_msg_meta msg_meta;
Mohammed Javid616bb992017-10-03 13:10:05 +0530573 struct ipa_wan_msg cache_wan_msg;
Amir Levy9659e592016-10-27 18:08:27 +0300574
575 wan_msg = kzalloc(sizeof(struct ipa_wan_msg), GFP_KERNEL);
576 if (!wan_msg) {
577 IPAERR("no memory\n");
578 return -ENOMEM;
579 }
580
Amir Levy479cfdd2017-10-26 12:23:14 +0300581 if (copy_from_user(wan_msg, (const void __user *)usr_param,
Amir Levy9659e592016-10-27 18:08:27 +0300582 sizeof(struct ipa_wan_msg))) {
583 kfree(wan_msg);
584 return -EFAULT;
585 }
586
Mohammed Javid616bb992017-10-03 13:10:05 +0530587 memcpy(&cache_wan_msg, wan_msg, sizeof(cache_wan_msg));
588
Amir Levy9659e592016-10-27 18:08:27 +0300589 memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
590 msg_meta.msg_type = msg_type;
591 msg_meta.msg_len = sizeof(struct ipa_wan_msg);
592 retval = ipa3_send_msg(&msg_meta, wan_msg, ipa3_wan_msg_free_cb);
593 if (retval) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530594 IPAERR_RL("ipa3_send_msg failed: %d\n", retval);
Amir Levy9659e592016-10-27 18:08:27 +0300595 kfree(wan_msg);
596 return retval;
597 }
598
Mohammed Javidb4b5ef42017-08-29 01:05:46 +0530599 if (is_cache) {
600 mutex_lock(&ipa3_ctx->ipa_cne_evt_lock);
601
602 /* cache the cne event */
603 memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[
604 ipa3_ctx->num_ipa_cne_evt_req].wan_msg,
Mohammed Javid616bb992017-10-03 13:10:05 +0530605 &cache_wan_msg,
606 sizeof(cache_wan_msg));
Mohammed Javidb4b5ef42017-08-29 01:05:46 +0530607
608 memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[
609 ipa3_ctx->num_ipa_cne_evt_req].msg_meta,
610 &msg_meta,
611 sizeof(struct ipa_msg_meta));
612
613 ipa3_ctx->num_ipa_cne_evt_req++;
614 ipa3_ctx->num_ipa_cne_evt_req %= IPA_MAX_NUM_REQ_CACHE;
615 mutex_unlock(&ipa3_ctx->ipa_cne_evt_lock);
616 }
617
Amir Levy9659e592016-10-27 18:08:27 +0300618 return 0;
619}
620
Shihuan Liuc3174f52017-05-04 15:59:13 -0700621static void ipa3_vlan_l2tp_msg_free_cb(void *buff, u32 len, u32 type)
622{
623 if (!buff) {
624 IPAERR("Null buffer\n");
625 return;
626 }
627
628 if (type != ADD_VLAN_IFACE &&
629 type != DEL_VLAN_IFACE &&
630 type != ADD_L2TP_VLAN_MAPPING &&
631 type != DEL_L2TP_VLAN_MAPPING) {
632 IPAERR("Wrong type given. buff %pK type %d\n", buff, type);
633 return;
634 }
635
636 kfree(buff);
637}
638
639static int ipa3_send_vlan_l2tp_msg(unsigned long usr_param, uint8_t msg_type)
640{
641 int retval;
642 struct ipa_ioc_vlan_iface_info *vlan_info;
643 struct ipa_ioc_l2tp_vlan_mapping_info *mapping_info;
644 struct ipa_msg_meta msg_meta;
645
646 if (msg_type == ADD_VLAN_IFACE ||
647 msg_type == DEL_VLAN_IFACE) {
648 vlan_info = kzalloc(sizeof(struct ipa_ioc_vlan_iface_info),
649 GFP_KERNEL);
650 if (!vlan_info) {
651 IPAERR("no memory\n");
652 return -ENOMEM;
653 }
654
655 if (copy_from_user((u8 *)vlan_info, (void __user *)usr_param,
656 sizeof(struct ipa_ioc_vlan_iface_info))) {
657 kfree(vlan_info);
658 return -EFAULT;
659 }
660
661 memset(&msg_meta, 0, sizeof(msg_meta));
662 msg_meta.msg_type = msg_type;
663 msg_meta.msg_len = sizeof(struct ipa_ioc_vlan_iface_info);
664 retval = ipa3_send_msg(&msg_meta, vlan_info,
665 ipa3_vlan_l2tp_msg_free_cb);
666 if (retval) {
667 IPAERR("ipa3_send_msg failed: %d\n", retval);
668 kfree(vlan_info);
669 return retval;
670 }
671 } else if (msg_type == ADD_L2TP_VLAN_MAPPING ||
672 msg_type == DEL_L2TP_VLAN_MAPPING) {
673 mapping_info = kzalloc(sizeof(struct
674 ipa_ioc_l2tp_vlan_mapping_info), GFP_KERNEL);
675 if (!mapping_info) {
676 IPAERR("no memory\n");
677 return -ENOMEM;
678 }
679
680 if (copy_from_user((u8 *)mapping_info,
681 (void __user *)usr_param,
682 sizeof(struct ipa_ioc_l2tp_vlan_mapping_info))) {
683 kfree(mapping_info);
684 return -EFAULT;
685 }
686
687 memset(&msg_meta, 0, sizeof(msg_meta));
688 msg_meta.msg_type = msg_type;
689 msg_meta.msg_len = sizeof(struct
690 ipa_ioc_l2tp_vlan_mapping_info);
691 retval = ipa3_send_msg(&msg_meta, mapping_info,
692 ipa3_vlan_l2tp_msg_free_cb);
693 if (retval) {
694 IPAERR("ipa3_send_msg failed: %d\n", retval);
695 kfree(mapping_info);
696 return retval;
697 }
698 } else {
699 IPAERR("Unexpected event\n");
700 return -EFAULT;
701 }
702
703 return 0;
704}
Amir Levy9659e592016-10-27 18:08:27 +0300705
706static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
707{
708 int retval = 0;
709 u32 pyld_sz;
710 u8 header[128] = { 0 };
711 u8 *param = NULL;
712 struct ipa_ioc_nat_alloc_mem nat_mem;
Amir Levy479cfdd2017-10-26 12:23:14 +0300713 struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc;
Amir Levy9659e592016-10-27 18:08:27 +0300714 struct ipa_ioc_v4_nat_init nat_init;
Amir Levy479cfdd2017-10-26 12:23:14 +0300715 struct ipa_ioc_ipv6ct_init ipv6ct_init;
Amir Levy9659e592016-10-27 18:08:27 +0300716 struct ipa_ioc_v4_nat_del nat_del;
Amir Levy479cfdd2017-10-26 12:23:14 +0300717 struct ipa_ioc_nat_ipv6ct_table_del table_del;
Amir Levy05fccd02017-06-13 16:25:45 +0300718 struct ipa_ioc_nat_pdn_entry mdfy_pdn;
Amir Levy9659e592016-10-27 18:08:27 +0300719 struct ipa_ioc_rm_dependency rm_depend;
Amir Levy479cfdd2017-10-26 12:23:14 +0300720 struct ipa_ioc_nat_dma_cmd *table_dma_cmd;
Amir Levy9659e592016-10-27 18:08:27 +0300721 size_t sz;
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200722 int pre_entry;
Amir Levy9659e592016-10-27 18:08:27 +0300723
724 IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
725
Amir Levy9659e592016-10-27 18:08:27 +0300726 if (_IOC_TYPE(cmd) != IPA_IOC_MAGIC)
727 return -ENOTTY;
Amir Levy9659e592016-10-27 18:08:27 +0300728
Amir Levy05532622016-11-28 12:12:01 +0200729 if (!ipa3_is_ready()) {
730 IPAERR("IPA not ready, waiting for init completion\n");
731 wait_for_completion(&ipa3_ctx->init_completion_obj);
732 }
733
Amir Levy9659e592016-10-27 18:08:27 +0300734 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
735
736 switch (cmd) {
737 case IPA_IOC_ALLOC_NAT_MEM:
Amir Levy479cfdd2017-10-26 12:23:14 +0300738 if (copy_from_user(&nat_mem, (const void __user *)arg,
739 sizeof(struct ipa_ioc_nat_alloc_mem))) {
Amir Levy9659e592016-10-27 18:08:27 +0300740 retval = -EFAULT;
741 break;
742 }
743 /* null terminate the string */
744 nat_mem.dev_name[IPA_RESOURCE_NAME_MAX - 1] = '\0';
745
746 if (ipa3_allocate_nat_device(&nat_mem)) {
747 retval = -EFAULT;
748 break;
749 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300750 if (copy_to_user((void __user *)arg, &nat_mem,
751 sizeof(struct ipa_ioc_nat_alloc_mem))) {
Amir Levy9659e592016-10-27 18:08:27 +0300752 retval = -EFAULT;
753 break;
754 }
755 break;
Amir Levy479cfdd2017-10-26 12:23:14 +0300756 case IPA_IOC_ALLOC_NAT_TABLE:
757 if (copy_from_user(&table_alloc, (const void __user *)arg,
758 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc))) {
759 retval = -EFAULT;
760 break;
761 }
762
763 if (ipa3_allocate_nat_table(&table_alloc)) {
764 retval = -EFAULT;
765 break;
766 }
767 if (table_alloc.offset &&
768 copy_to_user((void __user *)arg, &table_alloc, sizeof(
769 struct ipa_ioc_nat_ipv6ct_table_alloc))) {
770 retval = -EFAULT;
771 break;
772 }
773 break;
774
775 case IPA_IOC_ALLOC_IPV6CT_TABLE:
776 if (copy_from_user(&table_alloc, (const void __user *)arg,
777 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc))) {
778 retval = -EFAULT;
779 break;
780 }
781
782 if (ipa3_allocate_ipv6ct_table(&table_alloc)) {
783 retval = -EFAULT;
784 break;
785 }
786 if (table_alloc.offset &&
787 copy_to_user((void __user *)arg, &table_alloc, sizeof(
788 struct ipa_ioc_nat_ipv6ct_table_alloc))) {
789 retval = -EFAULT;
790 break;
791 }
792 break;
793
Amir Levy9659e592016-10-27 18:08:27 +0300794 case IPA_IOC_V4_INIT_NAT:
Amir Levy479cfdd2017-10-26 12:23:14 +0300795 if (copy_from_user(&nat_init, (const void __user *)arg,
796 sizeof(struct ipa_ioc_v4_nat_init))) {
Amir Levy9659e592016-10-27 18:08:27 +0300797 retval = -EFAULT;
798 break;
799 }
800 if (ipa3_nat_init_cmd(&nat_init)) {
801 retval = -EFAULT;
802 break;
803 }
804 break;
805
Amir Levy479cfdd2017-10-26 12:23:14 +0300806 case IPA_IOC_INIT_IPV6CT_TABLE:
807 if (copy_from_user(&ipv6ct_init, (const void __user *)arg,
808 sizeof(struct ipa_ioc_ipv6ct_init))) {
Amir Levy9659e592016-10-27 18:08:27 +0300809 retval = -EFAULT;
810 break;
811 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300812 if (ipa3_ipv6ct_init_cmd(&ipv6ct_init)) {
813 retval = -EFAULT;
814 break;
815 }
816 break;
817
818 case IPA_IOC_TABLE_DMA_CMD:
819 table_dma_cmd = (struct ipa_ioc_nat_dma_cmd *)header;
820 if (copy_from_user(header, (const void __user *)arg,
821 sizeof(struct ipa_ioc_nat_dma_cmd))) {
822 retval = -EFAULT;
823 break;
824 }
825 pre_entry = table_dma_cmd->entries;
826 pyld_sz = sizeof(struct ipa_ioc_nat_dma_cmd) +
827 pre_entry * sizeof(struct ipa_ioc_nat_dma_one);
Amir Levy9659e592016-10-27 18:08:27 +0300828 param = kzalloc(pyld_sz, GFP_KERNEL);
829 if (!param) {
830 retval = -ENOMEM;
831 break;
832 }
833
Amir Levy479cfdd2017-10-26 12:23:14 +0300834 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300835 retval = -EFAULT;
836 break;
837 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300838 table_dma_cmd = (struct ipa_ioc_nat_dma_cmd *)param;
839
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200840 /* add check in case user-space module compromised */
Amir Levy479cfdd2017-10-26 12:23:14 +0300841 if (unlikely(table_dma_cmd->entries != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530842 IPAERR_RL("current %d pre %d\n",
Amir Levy479cfdd2017-10-26 12:23:14 +0300843 table_dma_cmd->entries, pre_entry);
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200844 retval = -EFAULT;
845 break;
846 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300847 if (ipa3_table_dma_cmd(table_dma_cmd)) {
Amir Levy9659e592016-10-27 18:08:27 +0300848 retval = -EFAULT;
849 break;
850 }
851 break;
852
853 case IPA_IOC_V4_DEL_NAT:
Amir Levy479cfdd2017-10-26 12:23:14 +0300854 if (copy_from_user(&nat_del, (const void __user *)arg,
855 sizeof(struct ipa_ioc_v4_nat_del))) {
Amir Levy9659e592016-10-27 18:08:27 +0300856 retval = -EFAULT;
857 break;
858 }
859 if (ipa3_nat_del_cmd(&nat_del)) {
860 retval = -EFAULT;
861 break;
862 }
863 break;
864
Amir Levy479cfdd2017-10-26 12:23:14 +0300865 case IPA_IOC_DEL_NAT_TABLE:
866 if (copy_from_user(&table_del, (const void __user *)arg,
867 sizeof(struct ipa_ioc_nat_ipv6ct_table_del))) {
868 retval = -EFAULT;
869 break;
870 }
871 if (ipa3_del_nat_table(&table_del)) {
872 retval = -EFAULT;
873 break;
874 }
875 break;
876
877 case IPA_IOC_DEL_IPV6CT_TABLE:
878 if (copy_from_user(&table_del, (const void __user *)arg,
879 sizeof(struct ipa_ioc_nat_ipv6ct_table_del))) {
880 retval = -EFAULT;
881 break;
882 }
883 if (ipa3_del_ipv6ct_table(&table_del)) {
884 retval = -EFAULT;
885 break;
886 }
887 break;
888
Amir Levy05fccd02017-06-13 16:25:45 +0300889 case IPA_IOC_NAT_MODIFY_PDN:
Amir Levy479cfdd2017-10-26 12:23:14 +0300890 if (copy_from_user(&mdfy_pdn, (const void __user *)arg,
Amir Levy05fccd02017-06-13 16:25:45 +0300891 sizeof(struct ipa_ioc_nat_pdn_entry))) {
892 retval = -EFAULT;
893 break;
894 }
Amir Levydc65f4c2017-07-06 09:49:50 +0300895 if (ipa3_nat_mdfy_pdn(&mdfy_pdn)) {
Amir Levy05fccd02017-06-13 16:25:45 +0300896 retval = -EFAULT;
897 break;
898 }
899 break;
900
Amir Levy9659e592016-10-27 18:08:27 +0300901 case IPA_IOC_ADD_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +0300902 if (copy_from_user(header, (const void __user *)arg,
903 sizeof(struct ipa_ioc_add_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +0300904 retval = -EFAULT;
905 break;
906 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200907 pre_entry =
908 ((struct ipa_ioc_add_hdr *)header)->num_hdrs;
Amir Levy9659e592016-10-27 18:08:27 +0300909 pyld_sz =
910 sizeof(struct ipa_ioc_add_hdr) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200911 pre_entry * sizeof(struct ipa_hdr_add);
Amir Levy9659e592016-10-27 18:08:27 +0300912 param = kzalloc(pyld_sz, GFP_KERNEL);
913 if (!param) {
914 retval = -ENOMEM;
915 break;
916 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300917 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300918 retval = -EFAULT;
919 break;
920 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200921 /* add check in case user-space module compromised */
922 if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs
923 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530924 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200925 ((struct ipa_ioc_add_hdr *)param)->num_hdrs,
926 pre_entry);
927 retval = -EFAULT;
928 break;
929 }
Amir Levy9659e592016-10-27 18:08:27 +0300930 if (ipa3_add_hdr((struct ipa_ioc_add_hdr *)param)) {
931 retval = -EFAULT;
932 break;
933 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300934 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300935 retval = -EFAULT;
936 break;
937 }
938 break;
939
940 case IPA_IOC_DEL_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +0300941 if (copy_from_user(header, (const void __user *)arg,
942 sizeof(struct ipa_ioc_del_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +0300943 retval = -EFAULT;
944 break;
945 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200946 pre_entry =
947 ((struct ipa_ioc_del_hdr *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +0300948 pyld_sz =
949 sizeof(struct ipa_ioc_del_hdr) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200950 pre_entry * sizeof(struct ipa_hdr_del);
Amir Levy9659e592016-10-27 18:08:27 +0300951 param = kzalloc(pyld_sz, GFP_KERNEL);
952 if (!param) {
953 retval = -ENOMEM;
954 break;
955 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300956 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300957 retval = -EFAULT;
958 break;
959 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200960 /* add check in case user-space module compromised */
961 if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls
962 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530963 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200964 ((struct ipa_ioc_del_hdr *)param)->num_hdls,
965 pre_entry);
966 retval = -EFAULT;
967 break;
968 }
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200969 if (ipa3_del_hdr_by_user((struct ipa_ioc_del_hdr *)param,
970 true)) {
Amir Levy9659e592016-10-27 18:08:27 +0300971 retval = -EFAULT;
972 break;
973 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300974 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300975 retval = -EFAULT;
976 break;
977 }
978 break;
979
980 case IPA_IOC_ADD_RT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +0300981 if (copy_from_user(header, (const void __user *)arg,
982 sizeof(struct ipa_ioc_add_rt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +0300983 retval = -EFAULT;
984 break;
985 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200986 pre_entry =
987 ((struct ipa_ioc_add_rt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +0300988 pyld_sz =
989 sizeof(struct ipa_ioc_add_rt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200990 pre_entry * sizeof(struct ipa_rt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +0300991 param = kzalloc(pyld_sz, GFP_KERNEL);
992 if (!param) {
993 retval = -ENOMEM;
994 break;
995 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300996 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +0300997 retval = -EFAULT;
998 break;
999 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001000 /* add check in case user-space module compromised */
1001 if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules
1002 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301003 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001004 ((struct ipa_ioc_add_rt_rule *)param)->
1005 num_rules,
1006 pre_entry);
1007 retval = -EFAULT;
1008 break;
1009 }
Amir Levy9659e592016-10-27 18:08:27 +03001010 if (ipa3_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) {
1011 retval = -EFAULT;
1012 break;
1013 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001014 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001015 retval = -EFAULT;
1016 break;
1017 }
1018 break;
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05301019
1020 case IPA_IOC_ADD_RT_RULE_EXT:
1021 if (copy_from_user(header,
1022 (const void __user *)arg,
1023 sizeof(struct ipa_ioc_add_rt_rule_ext))) {
1024 retval = -EFAULT;
1025 break;
1026 }
1027 pre_entry =
1028 ((struct ipa_ioc_add_rt_rule_ext *)header)->num_rules;
1029 pyld_sz =
1030 sizeof(struct ipa_ioc_add_rt_rule_ext) +
1031 pre_entry * sizeof(struct ipa_rt_rule_add_ext);
1032 param = kzalloc(pyld_sz, GFP_KERNEL);
1033 if (!param) {
1034 retval = -ENOMEM;
1035 break;
1036 }
1037 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
1038 retval = -EFAULT;
1039 break;
1040 }
1041 /* add check in case user-space module compromised */
1042 if (unlikely(
1043 ((struct ipa_ioc_add_rt_rule_ext *)param)->num_rules
1044 != pre_entry)) {
1045 IPAERR(" prevent memory corruption(%d not match %d)\n",
1046 ((struct ipa_ioc_add_rt_rule_ext *)param)->
1047 num_rules,
1048 pre_entry);
1049 retval = -EINVAL;
1050 break;
1051 }
1052 if (ipa3_add_rt_rule_ext(
1053 (struct ipa_ioc_add_rt_rule_ext *)param)) {
1054 retval = -EFAULT;
1055 break;
1056 }
1057 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
1058 retval = -EFAULT;
1059 break;
1060 }
1061 break;
Amir Levy9659e592016-10-27 18:08:27 +03001062 case IPA_IOC_ADD_RT_RULE_AFTER:
Amir Levy479cfdd2017-10-26 12:23:14 +03001063 if (copy_from_user(header, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001064 sizeof(struct ipa_ioc_add_rt_rule_after))) {
1065
1066 retval = -EFAULT;
1067 break;
1068 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001069 pre_entry =
1070 ((struct ipa_ioc_add_rt_rule_after *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001071 pyld_sz =
1072 sizeof(struct ipa_ioc_add_rt_rule_after) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001073 pre_entry * sizeof(struct ipa_rt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001074 param = kzalloc(pyld_sz, GFP_KERNEL);
1075 if (!param) {
1076 retval = -ENOMEM;
1077 break;
1078 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001079 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001080 retval = -EFAULT;
1081 break;
1082 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001083 /* add check in case user-space module compromised */
1084 if (unlikely(((struct ipa_ioc_add_rt_rule_after *)param)->
1085 num_rules != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301086 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001087 ((struct ipa_ioc_add_rt_rule_after *)param)->
1088 num_rules,
1089 pre_entry);
1090 retval = -EFAULT;
1091 break;
1092 }
Amir Levy9659e592016-10-27 18:08:27 +03001093 if (ipa3_add_rt_rule_after(
1094 (struct ipa_ioc_add_rt_rule_after *)param)) {
1095
1096 retval = -EFAULT;
1097 break;
1098 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001099 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001100 retval = -EFAULT;
1101 break;
1102 }
1103 break;
1104
1105 case IPA_IOC_MDFY_RT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001106 if (copy_from_user(header, (const void __user *)arg,
1107 sizeof(struct ipa_ioc_mdfy_rt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001108 retval = -EFAULT;
1109 break;
1110 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001111 pre_entry =
1112 ((struct ipa_ioc_mdfy_rt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001113 pyld_sz =
1114 sizeof(struct ipa_ioc_mdfy_rt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001115 pre_entry * sizeof(struct ipa_rt_rule_mdfy);
Amir Levy9659e592016-10-27 18:08:27 +03001116 param = kzalloc(pyld_sz, GFP_KERNEL);
1117 if (!param) {
1118 retval = -ENOMEM;
1119 break;
1120 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001121 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001122 retval = -EFAULT;
1123 break;
1124 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001125 /* add check in case user-space module compromised */
1126 if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules
1127 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301128 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001129 ((struct ipa_ioc_mdfy_rt_rule *)param)->
1130 num_rules,
1131 pre_entry);
1132 retval = -EFAULT;
1133 break;
1134 }
Amir Levy9659e592016-10-27 18:08:27 +03001135 if (ipa3_mdfy_rt_rule((struct ipa_ioc_mdfy_rt_rule *)param)) {
1136 retval = -EFAULT;
1137 break;
1138 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001139 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001140 retval = -EFAULT;
1141 break;
1142 }
1143 break;
1144
1145 case IPA_IOC_DEL_RT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001146 if (copy_from_user(header, (const void __user *)arg,
1147 sizeof(struct ipa_ioc_del_rt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001148 retval = -EFAULT;
1149 break;
1150 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001151 pre_entry =
1152 ((struct ipa_ioc_del_rt_rule *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001153 pyld_sz =
1154 sizeof(struct ipa_ioc_del_rt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001155 pre_entry * sizeof(struct ipa_rt_rule_del);
Amir Levy9659e592016-10-27 18:08:27 +03001156 param = kzalloc(pyld_sz, GFP_KERNEL);
1157 if (!param) {
1158 retval = -ENOMEM;
1159 break;
1160 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001161 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001162 retval = -EFAULT;
1163 break;
1164 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001165 /* add check in case user-space module compromised */
1166 if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls
1167 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301168 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001169 ((struct ipa_ioc_del_rt_rule *)param)->num_hdls,
1170 pre_entry);
1171 retval = -EFAULT;
1172 break;
1173 }
Amir Levy9659e592016-10-27 18:08:27 +03001174 if (ipa3_del_rt_rule((struct ipa_ioc_del_rt_rule *)param)) {
1175 retval = -EFAULT;
1176 break;
1177 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001178 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001179 retval = -EFAULT;
1180 break;
1181 }
1182 break;
1183
1184 case IPA_IOC_ADD_FLT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001185 if (copy_from_user(header, (const void __user *)arg,
1186 sizeof(struct ipa_ioc_add_flt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001187 retval = -EFAULT;
1188 break;
1189 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001190 pre_entry =
1191 ((struct ipa_ioc_add_flt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001192 pyld_sz =
1193 sizeof(struct ipa_ioc_add_flt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001194 pre_entry * sizeof(struct ipa_flt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001195 param = kzalloc(pyld_sz, GFP_KERNEL);
1196 if (!param) {
1197 retval = -ENOMEM;
1198 break;
1199 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001200 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001201 retval = -EFAULT;
1202 break;
1203 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001204 /* add check in case user-space module compromised */
1205 if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules
1206 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301207 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001208 ((struct ipa_ioc_add_flt_rule *)param)->
1209 num_rules,
1210 pre_entry);
1211 retval = -EFAULT;
1212 break;
1213 }
Amir Levy9659e592016-10-27 18:08:27 +03001214 if (ipa3_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) {
1215 retval = -EFAULT;
1216 break;
1217 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001218 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001219 retval = -EFAULT;
1220 break;
1221 }
1222 break;
1223
1224 case IPA_IOC_ADD_FLT_RULE_AFTER:
Amir Levy479cfdd2017-10-26 12:23:14 +03001225 if (copy_from_user(header, (const void __user *)arg,
1226 sizeof(struct ipa_ioc_add_flt_rule_after))) {
Amir Levy9659e592016-10-27 18:08:27 +03001227
1228 retval = -EFAULT;
1229 break;
1230 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001231 pre_entry =
1232 ((struct ipa_ioc_add_flt_rule_after *)header)->
1233 num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001234 pyld_sz =
1235 sizeof(struct ipa_ioc_add_flt_rule_after) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001236 pre_entry * sizeof(struct ipa_flt_rule_add);
Amir Levy9659e592016-10-27 18:08:27 +03001237 param = kzalloc(pyld_sz, GFP_KERNEL);
1238 if (!param) {
1239 retval = -ENOMEM;
1240 break;
1241 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001242 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001243 retval = -EFAULT;
1244 break;
1245 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001246 /* add check in case user-space module compromised */
1247 if (unlikely(((struct ipa_ioc_add_flt_rule_after *)param)->
1248 num_rules != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301249 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001250 ((struct ipa_ioc_add_flt_rule_after *)param)->
1251 num_rules,
1252 pre_entry);
1253 retval = -EFAULT;
1254 break;
1255 }
Amir Levy9659e592016-10-27 18:08:27 +03001256 if (ipa3_add_flt_rule_after(
1257 (struct ipa_ioc_add_flt_rule_after *)param)) {
1258 retval = -EFAULT;
1259 break;
1260 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001261 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001262 retval = -EFAULT;
1263 break;
1264 }
1265 break;
1266
1267 case IPA_IOC_DEL_FLT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001268 if (copy_from_user(header, (const void __user *)arg,
1269 sizeof(struct ipa_ioc_del_flt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001270 retval = -EFAULT;
1271 break;
1272 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001273 pre_entry =
1274 ((struct ipa_ioc_del_flt_rule *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001275 pyld_sz =
1276 sizeof(struct ipa_ioc_del_flt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001277 pre_entry * sizeof(struct ipa_flt_rule_del);
Amir Levy9659e592016-10-27 18:08:27 +03001278 param = kzalloc(pyld_sz, GFP_KERNEL);
1279 if (!param) {
1280 retval = -ENOMEM;
1281 break;
1282 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001283 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001284 retval = -EFAULT;
1285 break;
1286 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001287 /* add check in case user-space module compromised */
1288 if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls
1289 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301290 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001291 ((struct ipa_ioc_del_flt_rule *)param)->
1292 num_hdls,
1293 pre_entry);
1294 retval = -EFAULT;
1295 break;
1296 }
Amir Levy9659e592016-10-27 18:08:27 +03001297 if (ipa3_del_flt_rule((struct ipa_ioc_del_flt_rule *)param)) {
1298 retval = -EFAULT;
1299 break;
1300 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001301 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001302 retval = -EFAULT;
1303 break;
1304 }
1305 break;
1306
1307 case IPA_IOC_MDFY_FLT_RULE:
Amir Levy479cfdd2017-10-26 12:23:14 +03001308 if (copy_from_user(header, (const void __user *)arg,
1309 sizeof(struct ipa_ioc_mdfy_flt_rule))) {
Amir Levy9659e592016-10-27 18:08:27 +03001310 retval = -EFAULT;
1311 break;
1312 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001313 pre_entry =
1314 ((struct ipa_ioc_mdfy_flt_rule *)header)->num_rules;
Amir Levy9659e592016-10-27 18:08:27 +03001315 pyld_sz =
1316 sizeof(struct ipa_ioc_mdfy_flt_rule) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001317 pre_entry * sizeof(struct ipa_flt_rule_mdfy);
Amir Levy9659e592016-10-27 18:08:27 +03001318 param = kzalloc(pyld_sz, GFP_KERNEL);
1319 if (!param) {
1320 retval = -ENOMEM;
1321 break;
1322 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001323 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001324 retval = -EFAULT;
1325 break;
1326 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001327 /* add check in case user-space module compromised */
1328 if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules
1329 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301330 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001331 ((struct ipa_ioc_mdfy_flt_rule *)param)->
1332 num_rules,
1333 pre_entry);
1334 retval = -EFAULT;
1335 break;
1336 }
Amir Levy9659e592016-10-27 18:08:27 +03001337 if (ipa3_mdfy_flt_rule((struct ipa_ioc_mdfy_flt_rule *)param)) {
1338 retval = -EFAULT;
1339 break;
1340 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001341 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001342 retval = -EFAULT;
1343 break;
1344 }
1345 break;
1346
1347 case IPA_IOC_COMMIT_HDR:
1348 retval = ipa3_commit_hdr();
1349 break;
1350 case IPA_IOC_RESET_HDR:
1351 retval = ipa3_reset_hdr();
1352 break;
1353 case IPA_IOC_COMMIT_RT:
1354 retval = ipa3_commit_rt(arg);
1355 break;
1356 case IPA_IOC_RESET_RT:
1357 retval = ipa3_reset_rt(arg);
1358 break;
1359 case IPA_IOC_COMMIT_FLT:
1360 retval = ipa3_commit_flt(arg);
1361 break;
1362 case IPA_IOC_RESET_FLT:
1363 retval = ipa3_reset_flt(arg);
1364 break;
1365 case IPA_IOC_GET_RT_TBL:
Amir Levy479cfdd2017-10-26 12:23:14 +03001366 if (copy_from_user(header, (const void __user *)arg,
1367 sizeof(struct ipa_ioc_get_rt_tbl))) {
Amir Levy9659e592016-10-27 18:08:27 +03001368 retval = -EFAULT;
1369 break;
1370 }
1371 if (ipa3_get_rt_tbl((struct ipa_ioc_get_rt_tbl *)header)) {
1372 retval = -EFAULT;
1373 break;
1374 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001375 if (copy_to_user((void __user *)arg, header,
Amir Levy9659e592016-10-27 18:08:27 +03001376 sizeof(struct ipa_ioc_get_rt_tbl))) {
1377 retval = -EFAULT;
1378 break;
1379 }
1380 break;
1381 case IPA_IOC_PUT_RT_TBL:
1382 retval = ipa3_put_rt_tbl(arg);
1383 break;
1384 case IPA_IOC_GET_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +03001385 if (copy_from_user(header, (const void __user *)arg,
1386 sizeof(struct ipa_ioc_get_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001387 retval = -EFAULT;
1388 break;
1389 }
1390 if (ipa3_get_hdr((struct ipa_ioc_get_hdr *)header)) {
1391 retval = -EFAULT;
1392 break;
1393 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001394 if (copy_to_user((void __user *)arg, header,
1395 sizeof(struct ipa_ioc_get_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001396 retval = -EFAULT;
1397 break;
1398 }
1399 break;
1400 case IPA_IOC_PUT_HDR:
1401 retval = ipa3_put_hdr(arg);
1402 break;
1403 case IPA_IOC_SET_FLT:
1404 retval = ipa3_cfg_filter(arg);
1405 break;
1406 case IPA_IOC_COPY_HDR:
Amir Levy479cfdd2017-10-26 12:23:14 +03001407 if (copy_from_user(header, (const void __user *)arg,
1408 sizeof(struct ipa_ioc_copy_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001409 retval = -EFAULT;
1410 break;
1411 }
1412 if (ipa3_copy_hdr((struct ipa_ioc_copy_hdr *)header)) {
1413 retval = -EFAULT;
1414 break;
1415 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001416 if (copy_to_user((void __user *)arg, header,
1417 sizeof(struct ipa_ioc_copy_hdr))) {
Amir Levy9659e592016-10-27 18:08:27 +03001418 retval = -EFAULT;
1419 break;
1420 }
1421 break;
1422 case IPA_IOC_QUERY_INTF:
Amir Levy479cfdd2017-10-26 12:23:14 +03001423 if (copy_from_user(header, (const void __user *)arg,
1424 sizeof(struct ipa_ioc_query_intf))) {
Amir Levy9659e592016-10-27 18:08:27 +03001425 retval = -EFAULT;
1426 break;
1427 }
1428 if (ipa3_query_intf((struct ipa_ioc_query_intf *)header)) {
1429 retval = -1;
1430 break;
1431 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001432 if (copy_to_user((void __user *)arg, header,
1433 sizeof(struct ipa_ioc_query_intf))) {
Amir Levy9659e592016-10-27 18:08:27 +03001434 retval = -EFAULT;
1435 break;
1436 }
1437 break;
1438 case IPA_IOC_QUERY_INTF_TX_PROPS:
1439 sz = sizeof(struct ipa_ioc_query_intf_tx_props);
Amir Levy479cfdd2017-10-26 12:23:14 +03001440 if (copy_from_user(header, (const void __user *)arg, sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001441 retval = -EFAULT;
1442 break;
1443 }
1444
1445 if (((struct ipa_ioc_query_intf_tx_props *)header)->num_tx_props
Amir Levy479cfdd2017-10-26 12:23:14 +03001446 > IPA_NUM_PROPS_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001447 retval = -EFAULT;
1448 break;
1449 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001450 pre_entry =
1451 ((struct ipa_ioc_query_intf_tx_props *)
1452 header)->num_tx_props;
1453 pyld_sz = sz + pre_entry *
Amir Levy9659e592016-10-27 18:08:27 +03001454 sizeof(struct ipa_ioc_tx_intf_prop);
1455 param = kzalloc(pyld_sz, GFP_KERNEL);
1456 if (!param) {
1457 retval = -ENOMEM;
1458 break;
1459 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001460 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001461 retval = -EFAULT;
1462 break;
1463 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001464 /* add check in case user-space module compromised */
1465 if (unlikely(((struct ipa_ioc_query_intf_tx_props *)
1466 param)->num_tx_props
1467 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301468 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001469 ((struct ipa_ioc_query_intf_tx_props *)
1470 param)->num_tx_props, pre_entry);
1471 retval = -EFAULT;
1472 break;
1473 }
Amir Levy9659e592016-10-27 18:08:27 +03001474 if (ipa3_query_intf_tx_props(
Amir Levy479cfdd2017-10-26 12:23:14 +03001475 (struct ipa_ioc_query_intf_tx_props *)param)) {
Amir Levy9659e592016-10-27 18:08:27 +03001476 retval = -1;
1477 break;
1478 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001479 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001480 retval = -EFAULT;
1481 break;
1482 }
1483 break;
1484 case IPA_IOC_QUERY_INTF_RX_PROPS:
1485 sz = sizeof(struct ipa_ioc_query_intf_rx_props);
Amir Levy479cfdd2017-10-26 12:23:14 +03001486 if (copy_from_user(header, (const void __user *)arg, sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001487 retval = -EFAULT;
1488 break;
1489 }
1490
1491 if (((struct ipa_ioc_query_intf_rx_props *)header)->num_rx_props
Amir Levy479cfdd2017-10-26 12:23:14 +03001492 > IPA_NUM_PROPS_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001493 retval = -EFAULT;
1494 break;
1495 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001496 pre_entry =
1497 ((struct ipa_ioc_query_intf_rx_props *)
1498 header)->num_rx_props;
1499 pyld_sz = sz + pre_entry *
Amir Levy9659e592016-10-27 18:08:27 +03001500 sizeof(struct ipa_ioc_rx_intf_prop);
1501 param = kzalloc(pyld_sz, GFP_KERNEL);
1502 if (!param) {
1503 retval = -ENOMEM;
1504 break;
1505 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001506 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001507 retval = -EFAULT;
1508 break;
1509 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001510 /* add check in case user-space module compromised */
1511 if (unlikely(((struct ipa_ioc_query_intf_rx_props *)
1512 param)->num_rx_props != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301513 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001514 ((struct ipa_ioc_query_intf_rx_props *)
1515 param)->num_rx_props, pre_entry);
1516 retval = -EFAULT;
1517 break;
1518 }
Amir Levy9659e592016-10-27 18:08:27 +03001519 if (ipa3_query_intf_rx_props(
Amir Levy479cfdd2017-10-26 12:23:14 +03001520 (struct ipa_ioc_query_intf_rx_props *)param)) {
Amir Levy9659e592016-10-27 18:08:27 +03001521 retval = -1;
1522 break;
1523 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001524 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001525 retval = -EFAULT;
1526 break;
1527 }
1528 break;
1529 case IPA_IOC_QUERY_INTF_EXT_PROPS:
1530 sz = sizeof(struct ipa_ioc_query_intf_ext_props);
Amir Levy479cfdd2017-10-26 12:23:14 +03001531 if (copy_from_user(header, (const void __user *)arg, sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001532 retval = -EFAULT;
1533 break;
1534 }
1535
1536 if (((struct ipa_ioc_query_intf_ext_props *)
Amir Levy479cfdd2017-10-26 12:23:14 +03001537 header)->num_ext_props > IPA_NUM_PROPS_MAX) {
Amir Levy9659e592016-10-27 18:08:27 +03001538 retval = -EFAULT;
1539 break;
1540 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001541 pre_entry =
1542 ((struct ipa_ioc_query_intf_ext_props *)
1543 header)->num_ext_props;
1544 pyld_sz = sz + pre_entry *
Amir Levy9659e592016-10-27 18:08:27 +03001545 sizeof(struct ipa_ioc_ext_intf_prop);
1546 param = kzalloc(pyld_sz, GFP_KERNEL);
1547 if (!param) {
1548 retval = -ENOMEM;
1549 break;
1550 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001551 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001552 retval = -EFAULT;
1553 break;
1554 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001555 /* add check in case user-space module compromised */
1556 if (unlikely(((struct ipa_ioc_query_intf_ext_props *)
1557 param)->num_ext_props != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301558 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001559 ((struct ipa_ioc_query_intf_ext_props *)
1560 param)->num_ext_props, pre_entry);
1561 retval = -EFAULT;
1562 break;
1563 }
Amir Levy9659e592016-10-27 18:08:27 +03001564 if (ipa3_query_intf_ext_props(
Amir Levy479cfdd2017-10-26 12:23:14 +03001565 (struct ipa_ioc_query_intf_ext_props *)param)) {
Amir Levy9659e592016-10-27 18:08:27 +03001566 retval = -1;
1567 break;
1568 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001569 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001570 retval = -EFAULT;
1571 break;
1572 }
1573 break;
1574 case IPA_IOC_PULL_MSG:
Amir Levy479cfdd2017-10-26 12:23:14 +03001575 if (copy_from_user(header, (const void __user *)arg,
1576 sizeof(struct ipa_msg_meta))) {
Amir Levy9659e592016-10-27 18:08:27 +03001577 retval = -EFAULT;
1578 break;
1579 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001580 pre_entry =
Amir Levy9659e592016-10-27 18:08:27 +03001581 ((struct ipa_msg_meta *)header)->msg_len;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001582 pyld_sz = sizeof(struct ipa_msg_meta) +
1583 pre_entry;
Amir Levy9659e592016-10-27 18:08:27 +03001584 param = kzalloc(pyld_sz, GFP_KERNEL);
1585 if (!param) {
1586 retval = -ENOMEM;
1587 break;
1588 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001589 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001590 retval = -EFAULT;
1591 break;
1592 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001593 /* add check in case user-space module compromised */
1594 if (unlikely(((struct ipa_msg_meta *)param)->msg_len
1595 != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301596 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001597 ((struct ipa_msg_meta *)param)->msg_len,
1598 pre_entry);
1599 retval = -EFAULT;
1600 break;
1601 }
Amir Levy9659e592016-10-27 18:08:27 +03001602 if (ipa3_pull_msg((struct ipa_msg_meta *)param,
Amir Levy479cfdd2017-10-26 12:23:14 +03001603 (char *)param + sizeof(struct ipa_msg_meta),
1604 ((struct ipa_msg_meta *)param)->msg_len) !=
1605 ((struct ipa_msg_meta *)param)->msg_len) {
Amir Levy9659e592016-10-27 18:08:27 +03001606 retval = -1;
1607 break;
1608 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001609 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001610 retval = -EFAULT;
1611 break;
1612 }
1613 break;
1614 case IPA_IOC_RM_ADD_DEPENDENCY:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001615 /* deprecate if IPA PM is used */
1616 if (ipa3_ctx->use_ipa_pm)
1617 return 0;
1618
Amir Levy479cfdd2017-10-26 12:23:14 +03001619 if (copy_from_user(&rm_depend, (const void __user *)arg,
1620 sizeof(struct ipa_ioc_rm_dependency))) {
Amir Levy9659e592016-10-27 18:08:27 +03001621 retval = -EFAULT;
1622 break;
1623 }
1624 retval = ipa_rm_add_dependency_from_ioctl(
1625 rm_depend.resource_name, rm_depend.depends_on_name);
1626 break;
1627 case IPA_IOC_RM_DEL_DEPENDENCY:
Michael Adisumarta3e350812017-09-18 14:54:36 -07001628 /* deprecate if IPA PM is used */
1629 if (ipa3_ctx->use_ipa_pm)
1630 return 0;
1631
Amir Levy479cfdd2017-10-26 12:23:14 +03001632 if (copy_from_user(&rm_depend, (const void __user *)arg,
1633 sizeof(struct ipa_ioc_rm_dependency))) {
Amir Levy9659e592016-10-27 18:08:27 +03001634 retval = -EFAULT;
1635 break;
1636 }
1637 retval = ipa_rm_delete_dependency_from_ioctl(
1638 rm_depend.resource_name, rm_depend.depends_on_name);
1639 break;
1640 case IPA_IOC_GENERATE_FLT_EQ:
1641 {
1642 struct ipa_ioc_generate_flt_eq flt_eq;
1643
Amir Levy479cfdd2017-10-26 12:23:14 +03001644 if (copy_from_user(&flt_eq, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001645 sizeof(struct ipa_ioc_generate_flt_eq))) {
1646 retval = -EFAULT;
1647 break;
1648 }
1649 if (ipahal_flt_generate_equation(flt_eq.ip,
1650 &flt_eq.attrib, &flt_eq.eq_attrib)) {
1651 retval = -EFAULT;
1652 break;
1653 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001654 if (copy_to_user((void __user *)arg, &flt_eq,
Amir Levy9659e592016-10-27 18:08:27 +03001655 sizeof(struct ipa_ioc_generate_flt_eq))) {
1656 retval = -EFAULT;
1657 break;
1658 }
1659 break;
1660 }
1661 case IPA_IOC_QUERY_EP_MAPPING:
1662 {
1663 retval = ipa3_get_ep_mapping(arg);
1664 break;
1665 }
1666 case IPA_IOC_QUERY_RT_TBL_INDEX:
Amir Levy479cfdd2017-10-26 12:23:14 +03001667 if (copy_from_user(header, (const void __user *)arg,
1668 sizeof(struct ipa_ioc_get_rt_tbl_indx))) {
Amir Levy9659e592016-10-27 18:08:27 +03001669 retval = -EFAULT;
1670 break;
1671 }
1672 if (ipa3_query_rt_index(
Amir Levy479cfdd2017-10-26 12:23:14 +03001673 (struct ipa_ioc_get_rt_tbl_indx *)header)) {
Amir Levy9659e592016-10-27 18:08:27 +03001674 retval = -EFAULT;
1675 break;
1676 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001677 if (copy_to_user((void __user *)arg, header,
1678 sizeof(struct ipa_ioc_get_rt_tbl_indx))) {
Amir Levy9659e592016-10-27 18:08:27 +03001679 retval = -EFAULT;
1680 break;
1681 }
1682 break;
1683 case IPA_IOC_WRITE_QMAPID:
Amir Levy479cfdd2017-10-26 12:23:14 +03001684 if (copy_from_user(header, (const void __user *)arg,
1685 sizeof(struct ipa_ioc_write_qmapid))) {
Amir Levy9659e592016-10-27 18:08:27 +03001686 retval = -EFAULT;
1687 break;
1688 }
1689 if (ipa3_write_qmap_id((struct ipa_ioc_write_qmapid *)header)) {
1690 retval = -EFAULT;
1691 break;
1692 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001693 if (copy_to_user((void __user *)arg, header,
1694 sizeof(struct ipa_ioc_write_qmapid))) {
Amir Levy9659e592016-10-27 18:08:27 +03001695 retval = -EFAULT;
1696 break;
1697 }
1698 break;
1699 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD:
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05301700 retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD, true);
Amir Levy9659e592016-10-27 18:08:27 +03001701 if (retval) {
1702 IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
1703 break;
1704 }
1705 break;
1706 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL:
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05301707 retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL, true);
Amir Levy9659e592016-10-27 18:08:27 +03001708 if (retval) {
1709 IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
1710 break;
1711 }
1712 break;
1713 case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED:
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05301714 retval = ipa3_send_wan_msg(arg, WAN_EMBMS_CONNECT, false);
Amir Levy9659e592016-10-27 18:08:27 +03001715 if (retval) {
1716 IPAERR("ipa3_send_wan_msg failed: %d\n", retval);
1717 break;
1718 }
1719 break;
1720 case IPA_IOC_ADD_HDR_PROC_CTX:
Amir Levy479cfdd2017-10-26 12:23:14 +03001721 if (copy_from_user(header, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001722 sizeof(struct ipa_ioc_add_hdr_proc_ctx))) {
1723 retval = -EFAULT;
1724 break;
1725 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001726 pre_entry =
1727 ((struct ipa_ioc_add_hdr_proc_ctx *)
1728 header)->num_proc_ctxs;
Amir Levy9659e592016-10-27 18:08:27 +03001729 pyld_sz =
1730 sizeof(struct ipa_ioc_add_hdr_proc_ctx) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001731 pre_entry * sizeof(struct ipa_hdr_proc_ctx_add);
Amir Levy9659e592016-10-27 18:08:27 +03001732 param = kzalloc(pyld_sz, GFP_KERNEL);
1733 if (!param) {
1734 retval = -ENOMEM;
1735 break;
1736 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001737 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001738 retval = -EFAULT;
1739 break;
1740 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001741 /* add check in case user-space module compromised */
1742 if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *)
1743 param)->num_proc_ctxs != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301744 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001745 ((struct ipa_ioc_add_hdr_proc_ctx *)
1746 param)->num_proc_ctxs, pre_entry);
1747 retval = -EFAULT;
1748 break;
1749 }
Amir Levy9659e592016-10-27 18:08:27 +03001750 if (ipa3_add_hdr_proc_ctx(
1751 (struct ipa_ioc_add_hdr_proc_ctx *)param)) {
1752 retval = -EFAULT;
1753 break;
1754 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001755 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001756 retval = -EFAULT;
1757 break;
1758 }
1759 break;
1760 case IPA_IOC_DEL_HDR_PROC_CTX:
Amir Levy479cfdd2017-10-26 12:23:14 +03001761 if (copy_from_user(header, (const void __user *)arg,
Amir Levy9659e592016-10-27 18:08:27 +03001762 sizeof(struct ipa_ioc_del_hdr_proc_ctx))) {
1763 retval = -EFAULT;
1764 break;
1765 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001766 pre_entry =
1767 ((struct ipa_ioc_del_hdr_proc_ctx *)header)->num_hdls;
Amir Levy9659e592016-10-27 18:08:27 +03001768 pyld_sz =
1769 sizeof(struct ipa_ioc_del_hdr_proc_ctx) +
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001770 pre_entry * sizeof(struct ipa_hdr_proc_ctx_del);
Amir Levy9659e592016-10-27 18:08:27 +03001771 param = kzalloc(pyld_sz, GFP_KERNEL);
1772 if (!param) {
1773 retval = -ENOMEM;
1774 break;
1775 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001776 if (copy_from_user(param, (const void __user *)arg, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001777 retval = -EFAULT;
1778 break;
1779 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001780 /* add check in case user-space module compromised */
1781 if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *)
1782 param)->num_hdls != pre_entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301783 IPAERR_RL("current %d pre %d\n",
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001784 ((struct ipa_ioc_del_hdr_proc_ctx *)param)->
1785 num_hdls,
1786 pre_entry);
1787 retval = -EFAULT;
1788 break;
1789 }
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02001790 if (ipa3_del_hdr_proc_ctx_by_user(
1791 (struct ipa_ioc_del_hdr_proc_ctx *)param, true)) {
Amir Levy9659e592016-10-27 18:08:27 +03001792 retval = -EFAULT;
1793 break;
1794 }
Amir Levy479cfdd2017-10-26 12:23:14 +03001795 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001796 retval = -EFAULT;
1797 break;
1798 }
1799 break;
1800
1801 case IPA_IOC_GET_HW_VERSION:
1802 pyld_sz = sizeof(enum ipa_hw_type);
1803 param = kzalloc(pyld_sz, GFP_KERNEL);
1804 if (!param) {
1805 retval = -ENOMEM;
1806 break;
1807 }
1808 memcpy(param, &ipa3_ctx->ipa_hw_type, pyld_sz);
Amir Levy479cfdd2017-10-26 12:23:14 +03001809 if (copy_to_user((void __user *)arg, param, pyld_sz)) {
Amir Levy9659e592016-10-27 18:08:27 +03001810 retval = -EFAULT;
1811 break;
1812 }
1813 break;
1814
Shihuan Liuc3174f52017-05-04 15:59:13 -07001815 case IPA_IOC_ADD_VLAN_IFACE:
1816 if (ipa3_send_vlan_l2tp_msg(arg, ADD_VLAN_IFACE)) {
1817 retval = -EFAULT;
1818 break;
1819 }
1820 break;
1821
1822 case IPA_IOC_DEL_VLAN_IFACE:
1823 if (ipa3_send_vlan_l2tp_msg(arg, DEL_VLAN_IFACE)) {
1824 retval = -EFAULT;
1825 break;
1826 }
1827 break;
1828
1829 case IPA_IOC_ADD_L2TP_VLAN_MAPPING:
1830 if (ipa3_send_vlan_l2tp_msg(arg, ADD_L2TP_VLAN_MAPPING)) {
1831 retval = -EFAULT;
1832 break;
1833 }
1834 break;
1835
1836 case IPA_IOC_DEL_L2TP_VLAN_MAPPING:
1837 if (ipa3_send_vlan_l2tp_msg(arg, DEL_L2TP_VLAN_MAPPING)) {
1838 retval = -EFAULT;
1839 break;
1840 }
1841 break;
1842
Amir Levy479cfdd2017-10-26 12:23:14 +03001843 default:
Amir Levy9659e592016-10-27 18:08:27 +03001844 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
1845 return -ENOTTY;
1846 }
1847 kfree(param);
1848 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
1849
1850 return retval;
1851}
1852
1853/**
1854* ipa3_setup_dflt_rt_tables() - Setup default routing tables
1855*
1856* Return codes:
1857* 0: success
1858* -ENOMEM: failed to allocate memory
1859* -EPERM: failed to add the tables
1860*/
1861int ipa3_setup_dflt_rt_tables(void)
1862{
1863 struct ipa_ioc_add_rt_rule *rt_rule;
1864 struct ipa_rt_rule_add *rt_rule_entry;
1865
1866 rt_rule =
Amir Levy479cfdd2017-10-26 12:23:14 +03001867 kzalloc(sizeof(struct ipa_ioc_add_rt_rule) + 1 *
1868 sizeof(struct ipa_rt_rule_add), GFP_KERNEL);
Amir Levy9659e592016-10-27 18:08:27 +03001869 if (!rt_rule) {
1870 IPAERR("fail to alloc mem\n");
1871 return -ENOMEM;
1872 }
1873 /* setup a default v4 route to point to Apps */
1874 rt_rule->num_rules = 1;
1875 rt_rule->commit = 1;
1876 rt_rule->ip = IPA_IP_v4;
1877 strlcpy(rt_rule->rt_tbl_name, IPA_DFLT_RT_TBL_NAME,
Amir Levy479cfdd2017-10-26 12:23:14 +03001878 IPA_RESOURCE_NAME_MAX);
Amir Levy9659e592016-10-27 18:08:27 +03001879
1880 rt_rule_entry = &rt_rule->rules[0];
1881 rt_rule_entry->at_rear = 1;
1882 rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
1883 rt_rule_entry->rule.hdr_hdl = ipa3_ctx->excp_hdr_hdl;
1884 rt_rule_entry->rule.retain_hdr = 1;
1885
1886 if (ipa3_add_rt_rule(rt_rule)) {
1887 IPAERR("fail to add dflt v4 rule\n");
1888 kfree(rt_rule);
1889 return -EPERM;
1890 }
1891 IPADBG("dflt v4 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
1892 ipa3_ctx->dflt_v4_rt_rule_hdl = rt_rule_entry->rt_rule_hdl;
1893
1894 /* setup a default v6 route to point to A5 */
1895 rt_rule->ip = IPA_IP_v6;
1896 if (ipa3_add_rt_rule(rt_rule)) {
1897 IPAERR("fail to add dflt v6 rule\n");
1898 kfree(rt_rule);
1899 return -EPERM;
1900 }
1901 IPADBG("dflt v6 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
1902 ipa3_ctx->dflt_v6_rt_rule_hdl = rt_rule_entry->rt_rule_hdl;
1903
1904 /*
1905 * because these tables are the very first to be added, they will both
1906 * have the same index (0) which is essential for programming the
1907 * "route" end-point config
1908 */
1909
1910 kfree(rt_rule);
1911
1912 return 0;
1913}
1914
1915static int ipa3_setup_exception_path(void)
1916{
1917 struct ipa_ioc_add_hdr *hdr;
1918 struct ipa_hdr_add *hdr_entry;
1919 struct ipahal_reg_route route = { 0 };
1920 int ret;
1921
1922 /* install the basic exception header */
1923 hdr = kzalloc(sizeof(struct ipa_ioc_add_hdr) + 1 *
1924 sizeof(struct ipa_hdr_add), GFP_KERNEL);
1925 if (!hdr) {
1926 IPAERR("fail to alloc exception hdr\n");
1927 return -ENOMEM;
1928 }
1929 hdr->num_hdrs = 1;
1930 hdr->commit = 1;
1931 hdr_entry = &hdr->hdr[0];
1932
1933 strlcpy(hdr_entry->name, IPA_LAN_RX_HDR_NAME, IPA_RESOURCE_NAME_MAX);
1934 hdr_entry->hdr_len = IPA_LAN_RX_HEADER_LENGTH;
1935
1936 if (ipa3_add_hdr(hdr)) {
1937 IPAERR("fail to add exception hdr\n");
1938 ret = -EPERM;
1939 goto bail;
1940 }
1941
1942 if (hdr_entry->status) {
1943 IPAERR("fail to add exception hdr\n");
1944 ret = -EPERM;
1945 goto bail;
1946 }
1947
1948 ipa3_ctx->excp_hdr_hdl = hdr_entry->hdr_hdl;
1949
1950 /* set the route register to pass exception packets to Apps */
1951 route.route_def_pipe = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS);
1952 route.route_frag_def_pipe = ipa3_get_ep_mapping(
1953 IPA_CLIENT_APPS_LAN_CONS);
1954 route.route_def_hdr_table = !ipa3_ctx->hdr_tbl_lcl;
1955 route.route_def_retain_hdr = 1;
1956
1957 if (ipa3_cfg_route(&route)) {
1958 IPAERR("fail to add exception hdr\n");
1959 ret = -EPERM;
1960 goto bail;
1961 }
1962
1963 ret = 0;
1964bail:
1965 kfree(hdr);
1966 return ret;
1967}
1968
1969static int ipa3_init_smem_region(int memory_region_size,
1970 int memory_region_offset)
1971{
1972 struct ipahal_imm_cmd_dma_shared_mem cmd;
1973 struct ipahal_imm_cmd_pyld *cmd_pyld;
1974 struct ipa3_desc desc;
1975 struct ipa_mem_buffer mem;
1976 int rc;
1977
1978 if (memory_region_size == 0)
1979 return 0;
1980
1981 memset(&desc, 0, sizeof(desc));
1982 memset(&cmd, 0, sizeof(cmd));
1983 memset(&mem, 0, sizeof(mem));
1984
1985 mem.size = memory_region_size;
1986 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
1987 &mem.phys_base, GFP_KERNEL);
1988 if (!mem.base) {
1989 IPAERR("failed to alloc DMA buff of size %d\n", mem.size);
1990 return -ENOMEM;
1991 }
1992
1993 memset(mem.base, 0, mem.size);
1994 cmd.is_read = false;
1995 cmd.skip_pipeline_clear = false;
1996 cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
1997 cmd.size = mem.size;
1998 cmd.system_addr = mem.phys_base;
1999 cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
2000 memory_region_offset;
2001 cmd_pyld = ipahal_construct_imm_cmd(
2002 IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
2003 if (!cmd_pyld) {
2004 IPAERR("failed to construct dma_shared_mem imm cmd\n");
2005 return -ENOMEM;
2006 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002007 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002008
2009 rc = ipa3_send_cmd(1, &desc);
2010 if (rc) {
2011 IPAERR("failed to send immediate command (error %d)\n", rc);
2012 rc = -EFAULT;
2013 }
2014
2015 ipahal_destroy_imm_cmd(cmd_pyld);
2016 dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base,
2017 mem.phys_base);
2018
2019 return rc;
2020}
2021
2022/**
2023* ipa3_init_q6_smem() - Initialize Q6 general memory and
2024* header memory regions in IPA.
2025*
2026* Return codes:
2027* 0: success
2028* -ENOMEM: failed to allocate dma memory
2029* -EFAULT: failed to send IPA command to initialize the memory
2030*/
2031int ipa3_init_q6_smem(void)
2032{
2033 int rc;
2034
2035 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
2036
2037 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_size),
2038 IPA_MEM_PART(modem_ofst));
2039 if (rc) {
2040 IPAERR("failed to initialize Modem RAM memory\n");
2041 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2042 return rc;
2043 }
2044
2045 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_hdr_size),
2046 IPA_MEM_PART(modem_hdr_ofst));
2047 if (rc) {
2048 IPAERR("failed to initialize Modem HDRs RAM memory\n");
2049 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2050 return rc;
2051 }
2052
2053 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_hdr_proc_ctx_size),
2054 IPA_MEM_PART(modem_hdr_proc_ctx_ofst));
2055 if (rc) {
2056 IPAERR("failed to initialize Modem proc ctx RAM memory\n");
2057 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2058 return rc;
2059 }
2060
2061 rc = ipa3_init_smem_region(IPA_MEM_PART(modem_comp_decomp_size),
2062 IPA_MEM_PART(modem_comp_decomp_ofst));
2063 if (rc) {
2064 IPAERR("failed to initialize Modem Comp/Decomp RAM memory\n");
2065 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2066 return rc;
2067 }
2068 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2069
2070 return rc;
2071}
2072
2073static void ipa3_destroy_imm(void *user1, int user2)
2074{
2075 ipahal_destroy_imm_cmd(user1);
2076}
2077
2078static void ipa3_q6_pipe_delay(bool delay)
2079{
2080 int client_idx;
2081 int ep_idx;
2082 struct ipa_ep_cfg_ctrl ep_ctrl;
2083
2084 memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
2085 ep_ctrl.ipa_ep_delay = delay;
2086
2087 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2088 if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
2089 ep_idx = ipa3_get_ep_mapping(client_idx);
2090 if (ep_idx == -1)
2091 continue;
2092
2093 ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n,
2094 ep_idx, &ep_ctrl);
2095 }
2096 }
2097}
2098
2099static void ipa3_q6_avoid_holb(void)
2100{
2101 int ep_idx;
2102 int client_idx;
2103 struct ipa_ep_cfg_ctrl ep_suspend;
2104 struct ipa_ep_cfg_holb ep_holb;
2105
2106 memset(&ep_suspend, 0, sizeof(ep_suspend));
2107 memset(&ep_holb, 0, sizeof(ep_holb));
2108
2109 ep_suspend.ipa_ep_suspend = true;
2110 ep_holb.tmr_val = 0;
2111 ep_holb.en = 1;
2112
2113 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2114 if (IPA_CLIENT_IS_Q6_CONS(client_idx)) {
2115 ep_idx = ipa3_get_ep_mapping(client_idx);
2116 if (ep_idx == -1)
2117 continue;
2118
Skylar Changde679dc2017-11-21 10:11:34 -08002119 /* from IPA 4.0 pipe suspend is not supported */
2120 if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
2121 ipahal_write_reg_n_fields(
2122 IPA_ENDP_INIT_CTRL_n,
2123 ep_idx, &ep_suspend);
2124
Amir Levy9659e592016-10-27 18:08:27 +03002125 /*
2126 * ipa3_cfg_ep_holb is not used here because we are
2127 * setting HOLB on Q6 pipes, and from APPS perspective
2128 * they are not valid, therefore, the above function
2129 * will fail.
2130 */
2131 ipahal_write_reg_n_fields(
2132 IPA_ENDP_INIT_HOL_BLOCK_TIMER_n,
2133 ep_idx, &ep_holb);
2134 ipahal_write_reg_n_fields(
2135 IPA_ENDP_INIT_HOL_BLOCK_EN_n,
2136 ep_idx, &ep_holb);
Amir Levy9659e592016-10-27 18:08:27 +03002137 }
2138 }
2139}
2140
Skylar Chang94692c92017-03-01 09:07:11 -08002141static void ipa3_halt_q6_cons_gsi_channels(void)
2142{
2143 int ep_idx;
2144 int client_idx;
2145 const struct ipa_gsi_ep_config *gsi_ep_cfg;
Michael Adisumartaf01e9fd2017-08-31 12:23:51 -07002146 int i;
Skylar Chang94692c92017-03-01 09:07:11 -08002147 int ret;
2148 int code = 0;
2149
2150 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2151 if (IPA_CLIENT_IS_Q6_CONS(client_idx)) {
2152 ep_idx = ipa3_get_ep_mapping(client_idx);
2153 if (ep_idx == -1)
2154 continue;
2155
Skylar Changc1f15312017-05-09 14:14:32 -07002156 gsi_ep_cfg = ipa3_get_gsi_ep_info(client_idx);
Skylar Chang94692c92017-03-01 09:07:11 -08002157 if (!gsi_ep_cfg) {
2158 IPAERR("failed to get GSI config\n");
2159 ipa_assert();
2160 return;
2161 }
2162
2163 ret = gsi_halt_channel_ee(
2164 gsi_ep_cfg->ipa_gsi_chan_num, gsi_ep_cfg->ee,
2165 &code);
Michael Adisumartaf01e9fd2017-08-31 12:23:51 -07002166 for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY &&
2167 ret == -GSI_STATUS_AGAIN; i++) {
2168 IPADBG(
2169 "ch %d ee %d with code %d\n is busy try again",
2170 gsi_ep_cfg->ipa_gsi_chan_num,
2171 gsi_ep_cfg->ee,
2172 code);
2173 usleep_range(IPA_GSI_CHANNEL_HALT_MIN_SLEEP,
2174 IPA_GSI_CHANNEL_HALT_MAX_SLEEP);
2175 ret = gsi_halt_channel_ee(
2176 gsi_ep_cfg->ipa_gsi_chan_num,
2177 gsi_ep_cfg->ee, &code);
2178 }
Skylar Chang94692c92017-03-01 09:07:11 -08002179 if (ret == GSI_STATUS_SUCCESS)
2180 IPADBG("halted gsi ch %d ee %d with code %d\n",
2181 gsi_ep_cfg->ipa_gsi_chan_num,
2182 gsi_ep_cfg->ee,
2183 code);
2184 else
2185 IPAERR("failed to halt ch %d ee %d code %d\n",
2186 gsi_ep_cfg->ipa_gsi_chan_num,
2187 gsi_ep_cfg->ee,
2188 code);
2189 }
2190 }
2191}
2192
2193
Amir Levy9659e592016-10-27 18:08:27 +03002194static int ipa3_q6_clean_q6_flt_tbls(enum ipa_ip_type ip,
2195 enum ipa_rule_type rlt)
2196{
2197 struct ipa3_desc *desc;
2198 struct ipahal_imm_cmd_dma_shared_mem cmd = {0};
2199 struct ipahal_imm_cmd_pyld **cmd_pyld;
2200 int retval = 0;
2201 int pipe_idx;
2202 int flt_idx = 0;
2203 int num_cmds = 0;
2204 int index;
2205 u32 lcl_addr_mem_part;
2206 u32 lcl_hdr_sz;
2207 struct ipa_mem_buffer mem;
2208
2209 IPADBG("Entry\n");
2210
2211 if ((ip >= IPA_IP_MAX) || (rlt >= IPA_RULE_TYPE_MAX)) {
2212 IPAERR("Input Err: ip=%d ; rlt=%d\n", ip, rlt);
2213 return -EINVAL;
2214 }
2215
2216 /* Up to filtering pipes we have filtering tables */
2217 desc = kcalloc(ipa3_ctx->ep_flt_num, sizeof(struct ipa3_desc),
2218 GFP_KERNEL);
2219 if (!desc) {
2220 IPAERR("failed to allocate memory\n");
2221 return -ENOMEM;
2222 }
2223
2224 cmd_pyld = kcalloc(ipa3_ctx->ep_flt_num,
2225 sizeof(struct ipahal_imm_cmd_pyld *), GFP_KERNEL);
2226 if (!cmd_pyld) {
2227 IPAERR("failed to allocate memory\n");
2228 retval = -ENOMEM;
2229 goto free_desc;
2230 }
2231
2232 if (ip == IPA_IP_v4) {
2233 if (rlt == IPA_RULE_HASHABLE) {
2234 lcl_addr_mem_part = IPA_MEM_PART(v4_flt_hash_ofst);
2235 lcl_hdr_sz = IPA_MEM_PART(v4_flt_hash_size);
2236 } else {
2237 lcl_addr_mem_part = IPA_MEM_PART(v4_flt_nhash_ofst);
2238 lcl_hdr_sz = IPA_MEM_PART(v4_flt_nhash_size);
2239 }
2240 } else {
2241 if (rlt == IPA_RULE_HASHABLE) {
2242 lcl_addr_mem_part = IPA_MEM_PART(v6_flt_hash_ofst);
2243 lcl_hdr_sz = IPA_MEM_PART(v6_flt_hash_size);
2244 } else {
2245 lcl_addr_mem_part = IPA_MEM_PART(v6_flt_nhash_ofst);
2246 lcl_hdr_sz = IPA_MEM_PART(v6_flt_nhash_size);
2247 }
2248 }
2249
2250 retval = ipahal_flt_generate_empty_img(1, lcl_hdr_sz, lcl_hdr_sz,
Amir Levy4dc79be2017-02-01 19:18:35 +02002251 0, &mem, true);
Amir Levy9659e592016-10-27 18:08:27 +03002252 if (retval) {
2253 IPAERR("failed to generate flt single tbl empty img\n");
2254 goto free_cmd_pyld;
2255 }
2256
2257 for (pipe_idx = 0; pipe_idx < ipa3_ctx->ipa_num_pipes; pipe_idx++) {
2258 if (!ipa_is_ep_support_flt(pipe_idx))
2259 continue;
2260
2261 /*
2262 * Iterating over all the filtering pipes which are either
2263 * invalid but connected or connected but not configured by AP.
2264 */
2265 if (!ipa3_ctx->ep[pipe_idx].valid ||
2266 ipa3_ctx->ep[pipe_idx].skip_ep_cfg) {
2267
Amir Levy479cfdd2017-10-26 12:23:14 +03002268 if (num_cmds >= ipa3_ctx->ep_flt_num) {
2269 IPAERR("number of commands is out of range\n");
2270 retval = -ENOBUFS;
2271 goto free_empty_img;
2272 }
2273
Amir Levy9659e592016-10-27 18:08:27 +03002274 cmd.is_read = false;
2275 cmd.skip_pipeline_clear = false;
2276 cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2277 cmd.size = mem.size;
2278 cmd.system_addr = mem.phys_base;
2279 cmd.local_addr =
2280 ipa3_ctx->smem_restricted_bytes +
2281 lcl_addr_mem_part +
2282 ipahal_get_hw_tbl_hdr_width() +
2283 flt_idx * ipahal_get_hw_tbl_hdr_width();
2284 cmd_pyld[num_cmds] = ipahal_construct_imm_cmd(
2285 IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
2286 if (!cmd_pyld[num_cmds]) {
2287 IPAERR("fail construct dma_shared_mem cmd\n");
2288 retval = -ENOMEM;
2289 goto free_empty_img;
2290 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002291 ipa3_init_imm_cmd_desc(&desc[num_cmds],
2292 cmd_pyld[num_cmds]);
2293 ++num_cmds;
Amir Levy9659e592016-10-27 18:08:27 +03002294 }
2295
Amir Levy479cfdd2017-10-26 12:23:14 +03002296 ++flt_idx;
Amir Levy9659e592016-10-27 18:08:27 +03002297 }
2298
2299 IPADBG("Sending %d descriptors for flt tbl clearing\n", num_cmds);
2300 retval = ipa3_send_cmd(num_cmds, desc);
2301 if (retval) {
2302 IPAERR("failed to send immediate command (err %d)\n", retval);
2303 retval = -EFAULT;
2304 }
2305
2306free_empty_img:
2307 ipahal_free_dma_mem(&mem);
2308free_cmd_pyld:
2309 for (index = 0; index < num_cmds; index++)
2310 ipahal_destroy_imm_cmd(cmd_pyld[index]);
2311 kfree(cmd_pyld);
2312free_desc:
2313 kfree(desc);
2314 return retval;
2315}
2316
2317static int ipa3_q6_clean_q6_rt_tbls(enum ipa_ip_type ip,
2318 enum ipa_rule_type rlt)
2319{
2320 struct ipa3_desc *desc;
2321 struct ipahal_imm_cmd_dma_shared_mem cmd = {0};
2322 struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
2323 int retval = 0;
2324 u32 modem_rt_index_lo;
2325 u32 modem_rt_index_hi;
2326 u32 lcl_addr_mem_part;
2327 u32 lcl_hdr_sz;
2328 struct ipa_mem_buffer mem;
2329
2330 IPADBG("Entry\n");
2331
2332 if ((ip >= IPA_IP_MAX) || (rlt >= IPA_RULE_TYPE_MAX)) {
2333 IPAERR("Input Err: ip=%d ; rlt=%d\n", ip, rlt);
2334 return -EINVAL;
2335 }
2336
2337 if (ip == IPA_IP_v4) {
2338 modem_rt_index_lo = IPA_MEM_PART(v4_modem_rt_index_lo);
2339 modem_rt_index_hi = IPA_MEM_PART(v4_modem_rt_index_hi);
2340 if (rlt == IPA_RULE_HASHABLE) {
2341 lcl_addr_mem_part = IPA_MEM_PART(v4_rt_hash_ofst);
2342 lcl_hdr_sz = IPA_MEM_PART(v4_flt_hash_size);
2343 } else {
2344 lcl_addr_mem_part = IPA_MEM_PART(v4_rt_nhash_ofst);
2345 lcl_hdr_sz = IPA_MEM_PART(v4_flt_nhash_size);
2346 }
2347 } else {
2348 modem_rt_index_lo = IPA_MEM_PART(v6_modem_rt_index_lo);
2349 modem_rt_index_hi = IPA_MEM_PART(v6_modem_rt_index_hi);
2350 if (rlt == IPA_RULE_HASHABLE) {
2351 lcl_addr_mem_part = IPA_MEM_PART(v6_rt_hash_ofst);
2352 lcl_hdr_sz = IPA_MEM_PART(v6_flt_hash_size);
2353 } else {
2354 lcl_addr_mem_part = IPA_MEM_PART(v6_rt_nhash_ofst);
2355 lcl_hdr_sz = IPA_MEM_PART(v6_flt_nhash_size);
2356 }
2357 }
2358
2359 retval = ipahal_rt_generate_empty_img(
2360 modem_rt_index_hi - modem_rt_index_lo + 1,
Amir Levy4dc79be2017-02-01 19:18:35 +02002361 lcl_hdr_sz, lcl_hdr_sz, &mem, true);
Amir Levy9659e592016-10-27 18:08:27 +03002362 if (retval) {
2363 IPAERR("fail generate empty rt img\n");
2364 return -ENOMEM;
2365 }
2366
2367 desc = kzalloc(sizeof(struct ipa3_desc), GFP_KERNEL);
2368 if (!desc) {
2369 IPAERR("failed to allocate memory\n");
2370 goto free_empty_img;
2371 }
2372
2373 cmd.is_read = false;
2374 cmd.skip_pipeline_clear = false;
2375 cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2376 cmd.size = mem.size;
2377 cmd.system_addr = mem.phys_base;
2378 cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
2379 lcl_addr_mem_part +
2380 modem_rt_index_lo * ipahal_get_hw_tbl_hdr_width();
2381 cmd_pyld = ipahal_construct_imm_cmd(
2382 IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
2383 if (!cmd_pyld) {
2384 IPAERR("failed to construct dma_shared_mem imm cmd\n");
2385 retval = -ENOMEM;
2386 goto free_desc;
2387 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002388 ipa3_init_imm_cmd_desc(desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002389
2390 IPADBG("Sending 1 descriptor for rt tbl clearing\n");
2391 retval = ipa3_send_cmd(1, desc);
2392 if (retval) {
2393 IPAERR("failed to send immediate command (err %d)\n", retval);
2394 retval = -EFAULT;
2395 }
2396
2397 ipahal_destroy_imm_cmd(cmd_pyld);
2398free_desc:
2399 kfree(desc);
2400free_empty_img:
2401 ipahal_free_dma_mem(&mem);
2402 return retval;
2403}
2404
2405static int ipa3_q6_clean_q6_tables(void)
2406{
2407 struct ipa3_desc *desc;
2408 struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
2409 struct ipahal_imm_cmd_register_write reg_write_cmd = {0};
2410 int retval;
2411 struct ipahal_reg_fltrt_hash_flush flush;
2412 struct ipahal_reg_valmask valmask;
2413
2414 IPADBG("Entry\n");
2415
2416
2417 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v4, IPA_RULE_HASHABLE)) {
2418 IPAERR("failed to clean q6 flt tbls (v4/hashable)\n");
2419 return -EFAULT;
2420 }
2421 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v6, IPA_RULE_HASHABLE)) {
2422 IPAERR("failed to clean q6 flt tbls (v6/hashable)\n");
2423 return -EFAULT;
2424 }
2425 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v4, IPA_RULE_NON_HASHABLE)) {
2426 IPAERR("failed to clean q6 flt tbls (v4/non-hashable)\n");
2427 return -EFAULT;
2428 }
2429 if (ipa3_q6_clean_q6_flt_tbls(IPA_IP_v6, IPA_RULE_NON_HASHABLE)) {
2430 IPAERR("failed to clean q6 flt tbls (v6/non-hashable)\n");
2431 return -EFAULT;
2432 }
2433
2434 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v4, IPA_RULE_HASHABLE)) {
2435 IPAERR("failed to clean q6 rt tbls (v4/hashable)\n");
2436 return -EFAULT;
2437 }
2438 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v6, IPA_RULE_HASHABLE)) {
2439 IPAERR("failed to clean q6 rt tbls (v6/hashable)\n");
2440 return -EFAULT;
2441 }
2442 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v4, IPA_RULE_NON_HASHABLE)) {
2443 IPAERR("failed to clean q6 rt tbls (v4/non-hashable)\n");
2444 return -EFAULT;
2445 }
2446 if (ipa3_q6_clean_q6_rt_tbls(IPA_IP_v6, IPA_RULE_NON_HASHABLE)) {
2447 IPAERR("failed to clean q6 rt tbls (v6/non-hashable)\n");
2448 return -EFAULT;
2449 }
2450
2451 /* Flush rules cache */
2452 desc = kzalloc(sizeof(struct ipa3_desc), GFP_KERNEL);
2453 if (!desc) {
2454 IPAERR("failed to allocate memory\n");
2455 return -ENOMEM;
2456 }
2457
2458 flush.v4_flt = true;
2459 flush.v4_rt = true;
2460 flush.v6_flt = true;
2461 flush.v6_rt = true;
2462 ipahal_get_fltrt_hash_flush_valmask(&flush, &valmask);
2463 reg_write_cmd.skip_pipeline_clear = false;
2464 reg_write_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2465 reg_write_cmd.offset = ipahal_get_reg_ofst(IPA_FILT_ROUT_HASH_FLUSH);
2466 reg_write_cmd.value = valmask.val;
2467 reg_write_cmd.value_mask = valmask.mask;
2468 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
2469 &reg_write_cmd, false);
2470 if (!cmd_pyld) {
2471 IPAERR("fail construct register_write imm cmd\n");
2472 retval = -EFAULT;
2473 goto bail_desc;
2474 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002475 ipa3_init_imm_cmd_desc(desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002476
2477 IPADBG("Sending 1 descriptor for tbls flush\n");
2478 retval = ipa3_send_cmd(1, desc);
2479 if (retval) {
2480 IPAERR("failed to send immediate command (err %d)\n", retval);
2481 retval = -EFAULT;
2482 }
2483
2484 ipahal_destroy_imm_cmd(cmd_pyld);
2485
2486bail_desc:
2487 kfree(desc);
2488 IPADBG("Done - retval = %d\n", retval);
2489 return retval;
2490}
2491
2492static int ipa3_q6_set_ex_path_to_apps(void)
2493{
2494 int ep_idx;
2495 int client_idx;
2496 struct ipa3_desc *desc;
2497 int num_descs = 0;
2498 int index;
2499 struct ipahal_imm_cmd_register_write reg_write;
2500 struct ipahal_imm_cmd_pyld *cmd_pyld;
2501 int retval;
Amir Levy9659e592016-10-27 18:08:27 +03002502
2503 desc = kcalloc(ipa3_ctx->ipa_num_pipes, sizeof(struct ipa3_desc),
2504 GFP_KERNEL);
2505 if (!desc) {
2506 IPAERR("failed to allocate memory\n");
2507 return -ENOMEM;
2508 }
2509
2510 /* Set the exception path to AP */
2511 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
2512 ep_idx = ipa3_get_ep_mapping(client_idx);
2513 if (ep_idx == -1)
2514 continue;
2515
Skylar Chang53137112017-05-12 17:13:13 -07002516 /* disable statuses for all modem controlled prod pipes */
2517 if (IPA_CLIENT_IS_Q6_PROD(client_idx) ||
2518 (ipa3_ctx->ep[ep_idx].valid &&
2519 ipa3_ctx->ep[ep_idx].skip_ep_cfg)) {
Amir Levy5807be32017-04-19 14:35:12 +03002520 ipa_assert_on(num_descs >= ipa3_ctx->ipa_num_pipes);
2521
2522 reg_write.skip_pipeline_clear = false;
2523 reg_write.pipeline_clear_options =
2524 IPAHAL_HPS_CLEAR;
2525 reg_write.offset =
2526 ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n,
2527 ep_idx);
2528 reg_write.value = 0;
2529 reg_write.value_mask = ~0;
2530 cmd_pyld = ipahal_construct_imm_cmd(
2531 IPA_IMM_CMD_REGISTER_WRITE, &reg_write, false);
2532 if (!cmd_pyld) {
2533 IPAERR("fail construct register_write cmd\n");
2534 ipa_assert();
2535 return -EFAULT;
2536 }
2537
Amir Levy479cfdd2017-10-26 12:23:14 +03002538 ipa3_init_imm_cmd_desc(&desc[num_descs], cmd_pyld);
Amir Levy5807be32017-04-19 14:35:12 +03002539 desc[num_descs].callback = ipa3_destroy_imm;
2540 desc[num_descs].user1 = cmd_pyld;
Amir Levy479cfdd2017-10-26 12:23:14 +03002541 ++num_descs;
Amir Levy5807be32017-04-19 14:35:12 +03002542 }
Amir Levy9659e592016-10-27 18:08:27 +03002543 }
2544
Gidon Studinski3021a6f2016-11-10 12:48:48 +02002545 /* Will wait 500msecs for IPA tag process completion */
Amir Levy9659e592016-10-27 18:08:27 +03002546 retval = ipa3_tag_process(desc, num_descs,
2547 msecs_to_jiffies(CLEANUP_TAG_PROCESS_TIMEOUT));
2548 if (retval) {
2549 IPAERR("TAG process failed! (error %d)\n", retval);
2550 /* For timeout error ipa3_destroy_imm cb will destroy user1 */
2551 if (retval != -ETIME) {
2552 for (index = 0; index < num_descs; index++)
2553 if (desc[index].callback)
2554 desc[index].callback(desc[index].user1,
2555 desc[index].user2);
2556 retval = -EINVAL;
2557 }
2558 }
2559
2560 kfree(desc);
2561
2562 return retval;
2563}
2564
2565/**
2566* ipa3_q6_pre_shutdown_cleanup() - A cleanup for all Q6 related configuration
2567* in IPA HW. This is performed in case of SSR.
2568*
2569* This is a mandatory procedure, in case one of the steps fails, the
2570* AP needs to restart.
2571*/
2572void ipa3_q6_pre_shutdown_cleanup(void)
2573{
2574 IPADBG_LOW("ENTER\n");
2575
2576 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
2577
2578 ipa3_q6_pipe_delay(true);
2579 ipa3_q6_avoid_holb();
2580 if (ipa3_q6_clean_q6_tables()) {
2581 IPAERR("Failed to clean Q6 tables\n");
2582 BUG();
2583 }
2584 if (ipa3_q6_set_ex_path_to_apps()) {
2585 IPAERR("Failed to redirect exceptions to APPS\n");
2586 BUG();
2587 }
2588 /* Remove delay from Q6 PRODs to avoid pending descriptors
2589 * on pipe reset procedure
2590 */
2591 ipa3_q6_pipe_delay(false);
2592
2593 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2594 IPADBG_LOW("Exit with success\n");
2595}
2596
2597/*
2598 * ipa3_q6_post_shutdown_cleanup() - As part of this cleanup
2599 * check if GSI channel related to Q6 producer client is empty.
2600 *
2601 * Q6 GSI channel emptiness is needed to garantee no descriptors with invalid
2602 * info are injected into IPA RX from IPA_IF, while modem is restarting.
2603 */
2604void ipa3_q6_post_shutdown_cleanup(void)
2605{
2606 int client_idx;
Skylar Changc1f15312017-05-09 14:14:32 -07002607 int ep_idx;
Amir Levy9659e592016-10-27 18:08:27 +03002608
2609 IPADBG_LOW("ENTER\n");
Amir Levy9659e592016-10-27 18:08:27 +03002610
2611 if (!ipa3_ctx->uc_ctx.uc_loaded) {
2612 IPAERR("uC is not loaded. Skipping\n");
2613 return;
2614 }
2615
Skylar Chang94692c92017-03-01 09:07:11 -08002616 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
2617
2618 /* Handle the issue where SUSPEND was removed for some reason */
2619 ipa3_q6_avoid_holb();
2620 ipa3_halt_q6_cons_gsi_channels();
2621
Amir Levy9659e592016-10-27 18:08:27 +03002622 for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
2623 if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
Skylar Changc1f15312017-05-09 14:14:32 -07002624 ep_idx = ipa3_get_ep_mapping(client_idx);
2625 if (ep_idx == -1)
2626 continue;
2627
Amir Levy9659e592016-10-27 18:08:27 +03002628 if (ipa3_uc_is_gsi_channel_empty(client_idx)) {
2629 IPAERR("fail to validate Q6 ch emptiness %d\n",
2630 client_idx);
2631 BUG();
2632 return;
2633 }
2634 }
2635
2636 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
2637 IPADBG_LOW("Exit with success\n");
2638}
2639
2640static inline void ipa3_sram_set_canary(u32 *sram_mmio, int offset)
2641{
2642 /* Set 4 bytes of CANARY before the offset */
2643 sram_mmio[(offset - 4) / 4] = IPA_MEM_CANARY_VAL;
2644}
2645
2646/**
Amir Levy9fadeca2017-04-25 10:18:32 +03002647 * _ipa_init_sram_v3() - Initialize IPA local SRAM.
Amir Levy9659e592016-10-27 18:08:27 +03002648 *
2649 * Return codes: 0 for success, negative value for failure
2650 */
Amir Levy9fadeca2017-04-25 10:18:32 +03002651int _ipa_init_sram_v3(void)
Amir Levy9659e592016-10-27 18:08:27 +03002652{
2653 u32 *ipa_sram_mmio;
2654 unsigned long phys_addr;
2655
2656 phys_addr = ipa3_ctx->ipa_wrapper_base +
2657 ipa3_ctx->ctrl->ipa_reg_base_ofst +
2658 ipahal_get_reg_n_ofst(IPA_SRAM_DIRECT_ACCESS_n,
2659 ipa3_ctx->smem_restricted_bytes / 4);
2660
2661 ipa_sram_mmio = ioremap(phys_addr, ipa3_ctx->smem_sz);
2662 if (!ipa_sram_mmio) {
2663 IPAERR("fail to ioremap IPA SRAM\n");
2664 return -ENOMEM;
2665 }
2666
2667 /* Consult with ipa_i.h on the location of the CANARY values */
2668 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_flt_hash_ofst) - 4);
2669 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_flt_hash_ofst));
2670 ipa3_sram_set_canary(ipa_sram_mmio,
2671 IPA_MEM_PART(v4_flt_nhash_ofst) - 4);
2672 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_flt_nhash_ofst));
2673 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_flt_hash_ofst) - 4);
2674 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_flt_hash_ofst));
2675 ipa3_sram_set_canary(ipa_sram_mmio,
2676 IPA_MEM_PART(v6_flt_nhash_ofst) - 4);
2677 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_flt_nhash_ofst));
2678 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_hash_ofst) - 4);
2679 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_hash_ofst));
2680 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_nhash_ofst) - 4);
2681 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v4_rt_nhash_ofst));
2682 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_hash_ofst) - 4);
2683 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_hash_ofst));
2684 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_nhash_ofst) - 4);
2685 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(v6_rt_nhash_ofst));
2686 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_hdr_ofst) - 4);
2687 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_hdr_ofst));
2688 ipa3_sram_set_canary(ipa_sram_mmio,
2689 IPA_MEM_PART(modem_hdr_proc_ctx_ofst) - 4);
2690 ipa3_sram_set_canary(ipa_sram_mmio,
2691 IPA_MEM_PART(modem_hdr_proc_ctx_ofst));
2692 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_ofst) - 4);
2693 ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_ofst));
Amir Levy9fadeca2017-04-25 10:18:32 +03002694 ipa3_sram_set_canary(ipa_sram_mmio,
2695 (ipa_get_hw_type() >= IPA_HW_v3_5) ?
2696 IPA_MEM_PART(uc_event_ring_ofst) :
2697 IPA_MEM_PART(end_ofst));
Amir Levy9659e592016-10-27 18:08:27 +03002698
2699 iounmap(ipa_sram_mmio);
2700
2701 return 0;
2702}
2703
2704/**
2705 * _ipa_init_hdr_v3_0() - Initialize IPA header block.
2706 *
2707 * Return codes: 0 for success, negative value for failure
2708 */
2709int _ipa_init_hdr_v3_0(void)
2710{
Amir Levy479cfdd2017-10-26 12:23:14 +03002711 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03002712 struct ipa_mem_buffer mem;
2713 struct ipahal_imm_cmd_hdr_init_local cmd = {0};
2714 struct ipahal_imm_cmd_pyld *cmd_pyld;
2715 struct ipahal_imm_cmd_dma_shared_mem dma_cmd = { 0 };
2716
2717 mem.size = IPA_MEM_PART(modem_hdr_size) + IPA_MEM_PART(apps_hdr_size);
2718 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size, &mem.phys_base,
2719 GFP_KERNEL);
2720 if (!mem.base) {
2721 IPAERR("fail to alloc DMA buff of size %d\n", mem.size);
2722 return -ENOMEM;
2723 }
2724 memset(mem.base, 0, mem.size);
2725
2726 cmd.hdr_table_addr = mem.phys_base;
2727 cmd.size_hdr_table = mem.size;
2728 cmd.hdr_addr = ipa3_ctx->smem_restricted_bytes +
2729 IPA_MEM_PART(modem_hdr_ofst);
2730 cmd_pyld = ipahal_construct_imm_cmd(
2731 IPA_IMM_CMD_HDR_INIT_LOCAL, &cmd, false);
2732 if (!cmd_pyld) {
2733 IPAERR("fail to construct hdr_init_local imm cmd\n");
2734 dma_free_coherent(ipa3_ctx->pdev,
2735 mem.size, mem.base,
2736 mem.phys_base);
2737 return -EFAULT;
2738 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002739 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002740 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
2741
2742 if (ipa3_send_cmd(1, &desc)) {
2743 IPAERR("fail to send immediate command\n");
2744 ipahal_destroy_imm_cmd(cmd_pyld);
2745 dma_free_coherent(ipa3_ctx->pdev,
2746 mem.size, mem.base,
2747 mem.phys_base);
2748 return -EFAULT;
2749 }
2750
2751 ipahal_destroy_imm_cmd(cmd_pyld);
2752 dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
2753
2754 mem.size = IPA_MEM_PART(modem_hdr_proc_ctx_size) +
2755 IPA_MEM_PART(apps_hdr_proc_ctx_size);
2756 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size, &mem.phys_base,
2757 GFP_KERNEL);
2758 if (!mem.base) {
2759 IPAERR("fail to alloc DMA buff of size %d\n", mem.size);
2760 return -ENOMEM;
2761 }
2762 memset(mem.base, 0, mem.size);
Amir Levy9659e592016-10-27 18:08:27 +03002763
2764 dma_cmd.is_read = false;
2765 dma_cmd.skip_pipeline_clear = false;
2766 dma_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
2767 dma_cmd.system_addr = mem.phys_base;
2768 dma_cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
2769 IPA_MEM_PART(modem_hdr_proc_ctx_ofst);
2770 dma_cmd.size = mem.size;
2771 cmd_pyld = ipahal_construct_imm_cmd(
2772 IPA_IMM_CMD_DMA_SHARED_MEM, &dma_cmd, false);
2773 if (!cmd_pyld) {
2774 IPAERR("fail to construct dma_shared_mem imm\n");
2775 dma_free_coherent(ipa3_ctx->pdev,
2776 mem.size, mem.base,
2777 mem.phys_base);
2778 return -EFAULT;
2779 }
Amir Levy479cfdd2017-10-26 12:23:14 +03002780 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002781 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
2782
2783 if (ipa3_send_cmd(1, &desc)) {
2784 IPAERR("fail to send immediate command\n");
2785 ipahal_destroy_imm_cmd(cmd_pyld);
2786 dma_free_coherent(ipa3_ctx->pdev,
2787 mem.size,
2788 mem.base,
2789 mem.phys_base);
2790 return -EFAULT;
2791 }
2792 ipahal_destroy_imm_cmd(cmd_pyld);
2793
2794 ipahal_write_reg(IPA_LOCAL_PKT_PROC_CNTXT_BASE, dma_cmd.local_addr);
2795
2796 dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
2797
2798 return 0;
2799}
2800
2801/**
2802 * _ipa_init_rt4_v3() - Initialize IPA routing block for IPv4.
2803 *
2804 * Return codes: 0 for success, negative value for failure
2805 */
2806int _ipa_init_rt4_v3(void)
2807{
Amir Levy479cfdd2017-10-26 12:23:14 +03002808 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03002809 struct ipa_mem_buffer mem;
2810 struct ipahal_imm_cmd_ip_v4_routing_init v4_cmd;
2811 struct ipahal_imm_cmd_pyld *cmd_pyld;
2812 int i;
2813 int rc = 0;
2814
2815 for (i = IPA_MEM_PART(v4_modem_rt_index_lo);
2816 i <= IPA_MEM_PART(v4_modem_rt_index_hi);
2817 i++)
2818 ipa3_ctx->rt_idx_bitmap[IPA_IP_v4] |= (1 << i);
2819 IPADBG("v4 rt bitmap 0x%lx\n", ipa3_ctx->rt_idx_bitmap[IPA_IP_v4]);
2820
2821 rc = ipahal_rt_generate_empty_img(IPA_MEM_PART(v4_rt_num_index),
2822 IPA_MEM_PART(v4_rt_hash_size), IPA_MEM_PART(v4_rt_nhash_size),
Amir Levy4dc79be2017-02-01 19:18:35 +02002823 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03002824 if (rc) {
2825 IPAERR("fail generate empty v4 rt img\n");
2826 return rc;
2827 }
2828
2829 v4_cmd.hash_rules_addr = mem.phys_base;
2830 v4_cmd.hash_rules_size = mem.size;
2831 v4_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
2832 IPA_MEM_PART(v4_rt_hash_ofst);
2833 v4_cmd.nhash_rules_addr = mem.phys_base;
2834 v4_cmd.nhash_rules_size = mem.size;
2835 v4_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
2836 IPA_MEM_PART(v4_rt_nhash_ofst);
2837 IPADBG("putting hashable routing IPv4 rules to phys 0x%x\n",
2838 v4_cmd.hash_local_addr);
2839 IPADBG("putting non-hashable routing IPv4 rules to phys 0x%x\n",
2840 v4_cmd.nhash_local_addr);
2841 cmd_pyld = ipahal_construct_imm_cmd(
2842 IPA_IMM_CMD_IP_V4_ROUTING_INIT, &v4_cmd, false);
2843 if (!cmd_pyld) {
2844 IPAERR("fail construct ip_v4_rt_init imm cmd\n");
2845 rc = -EPERM;
2846 goto free_mem;
2847 }
2848
Amir Levy479cfdd2017-10-26 12:23:14 +03002849 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002850 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
2851
2852 if (ipa3_send_cmd(1, &desc)) {
2853 IPAERR("fail to send immediate command\n");
2854 rc = -EFAULT;
2855 }
2856
2857 ipahal_destroy_imm_cmd(cmd_pyld);
2858
2859free_mem:
2860 ipahal_free_dma_mem(&mem);
2861 return rc;
2862}
2863
2864/**
2865 * _ipa_init_rt6_v3() - Initialize IPA routing block for IPv6.
2866 *
2867 * Return codes: 0 for success, negative value for failure
2868 */
2869int _ipa_init_rt6_v3(void)
2870{
Amir Levy479cfdd2017-10-26 12:23:14 +03002871 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03002872 struct ipa_mem_buffer mem;
2873 struct ipahal_imm_cmd_ip_v6_routing_init v6_cmd;
2874 struct ipahal_imm_cmd_pyld *cmd_pyld;
2875 int i;
2876 int rc = 0;
2877
2878 for (i = IPA_MEM_PART(v6_modem_rt_index_lo);
2879 i <= IPA_MEM_PART(v6_modem_rt_index_hi);
2880 i++)
2881 ipa3_ctx->rt_idx_bitmap[IPA_IP_v6] |= (1 << i);
2882 IPADBG("v6 rt bitmap 0x%lx\n", ipa3_ctx->rt_idx_bitmap[IPA_IP_v6]);
2883
2884 rc = ipahal_rt_generate_empty_img(IPA_MEM_PART(v6_rt_num_index),
2885 IPA_MEM_PART(v6_rt_hash_size), IPA_MEM_PART(v6_rt_nhash_size),
Amir Levy4dc79be2017-02-01 19:18:35 +02002886 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03002887 if (rc) {
2888 IPAERR("fail generate empty v6 rt img\n");
2889 return rc;
2890 }
2891
2892 v6_cmd.hash_rules_addr = mem.phys_base;
2893 v6_cmd.hash_rules_size = mem.size;
2894 v6_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
2895 IPA_MEM_PART(v6_rt_hash_ofst);
2896 v6_cmd.nhash_rules_addr = mem.phys_base;
2897 v6_cmd.nhash_rules_size = mem.size;
2898 v6_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
2899 IPA_MEM_PART(v6_rt_nhash_ofst);
2900 IPADBG("putting hashable routing IPv6 rules to phys 0x%x\n",
2901 v6_cmd.hash_local_addr);
2902 IPADBG("putting non-hashable routing IPv6 rules to phys 0x%x\n",
2903 v6_cmd.nhash_local_addr);
2904 cmd_pyld = ipahal_construct_imm_cmd(
2905 IPA_IMM_CMD_IP_V6_ROUTING_INIT, &v6_cmd, false);
2906 if (!cmd_pyld) {
2907 IPAERR("fail construct ip_v6_rt_init imm cmd\n");
2908 rc = -EPERM;
2909 goto free_mem;
2910 }
2911
Amir Levy479cfdd2017-10-26 12:23:14 +03002912 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002913 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
2914
2915 if (ipa3_send_cmd(1, &desc)) {
2916 IPAERR("fail to send immediate command\n");
2917 rc = -EFAULT;
2918 }
2919
2920 ipahal_destroy_imm_cmd(cmd_pyld);
2921
2922free_mem:
2923 ipahal_free_dma_mem(&mem);
2924 return rc;
2925}
2926
2927/**
2928 * _ipa_init_flt4_v3() - Initialize IPA filtering block for IPv4.
2929 *
2930 * Return codes: 0 for success, negative value for failure
2931 */
2932int _ipa_init_flt4_v3(void)
2933{
Amir Levy479cfdd2017-10-26 12:23:14 +03002934 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03002935 struct ipa_mem_buffer mem;
2936 struct ipahal_imm_cmd_ip_v4_filter_init v4_cmd;
2937 struct ipahal_imm_cmd_pyld *cmd_pyld;
2938 int rc;
2939
2940 rc = ipahal_flt_generate_empty_img(ipa3_ctx->ep_flt_num,
2941 IPA_MEM_PART(v4_flt_hash_size),
2942 IPA_MEM_PART(v4_flt_nhash_size), ipa3_ctx->ep_flt_bitmap,
Amir Levy4dc79be2017-02-01 19:18:35 +02002943 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03002944 if (rc) {
2945 IPAERR("fail generate empty v4 flt img\n");
2946 return rc;
2947 }
2948
2949 v4_cmd.hash_rules_addr = mem.phys_base;
2950 v4_cmd.hash_rules_size = mem.size;
2951 v4_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
2952 IPA_MEM_PART(v4_flt_hash_ofst);
2953 v4_cmd.nhash_rules_addr = mem.phys_base;
2954 v4_cmd.nhash_rules_size = mem.size;
2955 v4_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
2956 IPA_MEM_PART(v4_flt_nhash_ofst);
2957 IPADBG("putting hashable filtering IPv4 rules to phys 0x%x\n",
2958 v4_cmd.hash_local_addr);
2959 IPADBG("putting non-hashable filtering IPv4 rules to phys 0x%x\n",
2960 v4_cmd.nhash_local_addr);
2961 cmd_pyld = ipahal_construct_imm_cmd(
2962 IPA_IMM_CMD_IP_V4_FILTER_INIT, &v4_cmd, false);
2963 if (!cmd_pyld) {
2964 IPAERR("fail construct ip_v4_flt_init imm cmd\n");
2965 rc = -EPERM;
2966 goto free_mem;
2967 }
2968
Amir Levy479cfdd2017-10-26 12:23:14 +03002969 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03002970 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
2971
2972 if (ipa3_send_cmd(1, &desc)) {
2973 IPAERR("fail to send immediate command\n");
2974 rc = -EFAULT;
2975 }
2976
2977 ipahal_destroy_imm_cmd(cmd_pyld);
2978
2979free_mem:
2980 ipahal_free_dma_mem(&mem);
2981 return rc;
2982}
2983
2984/**
2985 * _ipa_init_flt6_v3() - Initialize IPA filtering block for IPv6.
2986 *
2987 * Return codes: 0 for success, negative value for failure
2988 */
2989int _ipa_init_flt6_v3(void)
2990{
Amir Levy479cfdd2017-10-26 12:23:14 +03002991 struct ipa3_desc desc;
Amir Levy9659e592016-10-27 18:08:27 +03002992 struct ipa_mem_buffer mem;
2993 struct ipahal_imm_cmd_ip_v6_filter_init v6_cmd;
2994 struct ipahal_imm_cmd_pyld *cmd_pyld;
2995 int rc;
2996
2997 rc = ipahal_flt_generate_empty_img(ipa3_ctx->ep_flt_num,
2998 IPA_MEM_PART(v6_flt_hash_size),
2999 IPA_MEM_PART(v6_flt_nhash_size), ipa3_ctx->ep_flt_bitmap,
Amir Levy4dc79be2017-02-01 19:18:35 +02003000 &mem, false);
Amir Levy9659e592016-10-27 18:08:27 +03003001 if (rc) {
3002 IPAERR("fail generate empty v6 flt img\n");
3003 return rc;
3004 }
3005
3006 v6_cmd.hash_rules_addr = mem.phys_base;
3007 v6_cmd.hash_rules_size = mem.size;
3008 v6_cmd.hash_local_addr = ipa3_ctx->smem_restricted_bytes +
3009 IPA_MEM_PART(v6_flt_hash_ofst);
3010 v6_cmd.nhash_rules_addr = mem.phys_base;
3011 v6_cmd.nhash_rules_size = mem.size;
3012 v6_cmd.nhash_local_addr = ipa3_ctx->smem_restricted_bytes +
3013 IPA_MEM_PART(v6_flt_nhash_ofst);
3014 IPADBG("putting hashable filtering IPv6 rules to phys 0x%x\n",
3015 v6_cmd.hash_local_addr);
3016 IPADBG("putting non-hashable filtering IPv6 rules to phys 0x%x\n",
3017 v6_cmd.nhash_local_addr);
3018
3019 cmd_pyld = ipahal_construct_imm_cmd(
3020 IPA_IMM_CMD_IP_V6_FILTER_INIT, &v6_cmd, false);
3021 if (!cmd_pyld) {
3022 IPAERR("fail construct ip_v6_flt_init imm cmd\n");
3023 rc = -EPERM;
3024 goto free_mem;
3025 }
3026
Amir Levy479cfdd2017-10-26 12:23:14 +03003027 ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +03003028 IPA_DUMP_BUFF(mem.base, mem.phys_base, mem.size);
3029
3030 if (ipa3_send_cmd(1, &desc)) {
3031 IPAERR("fail to send immediate command\n");
3032 rc = -EFAULT;
3033 }
3034
3035 ipahal_destroy_imm_cmd(cmd_pyld);
3036
3037free_mem:
3038 ipahal_free_dma_mem(&mem);
3039 return rc;
3040}
3041
3042static int ipa3_setup_flt_hash_tuple(void)
3043{
3044 int pipe_idx;
3045 struct ipahal_reg_hash_tuple tuple;
3046
3047 memset(&tuple, 0, sizeof(struct ipahal_reg_hash_tuple));
3048
3049 for (pipe_idx = 0; pipe_idx < ipa3_ctx->ipa_num_pipes ; pipe_idx++) {
3050 if (!ipa_is_ep_support_flt(pipe_idx))
3051 continue;
3052
3053 if (ipa_is_modem_pipe(pipe_idx))
3054 continue;
3055
3056 if (ipa3_set_flt_tuple_mask(pipe_idx, &tuple)) {
3057 IPAERR("failed to setup pipe %d flt tuple\n", pipe_idx);
3058 return -EFAULT;
3059 }
3060 }
3061
3062 return 0;
3063}
3064
3065static int ipa3_setup_rt_hash_tuple(void)
3066{
3067 int tbl_idx;
3068 struct ipahal_reg_hash_tuple tuple;
3069
3070 memset(&tuple, 0, sizeof(struct ipahal_reg_hash_tuple));
3071
3072 for (tbl_idx = 0;
3073 tbl_idx < max(IPA_MEM_PART(v6_rt_num_index),
3074 IPA_MEM_PART(v4_rt_num_index));
3075 tbl_idx++) {
3076
3077 if (tbl_idx >= IPA_MEM_PART(v4_modem_rt_index_lo) &&
3078 tbl_idx <= IPA_MEM_PART(v4_modem_rt_index_hi))
3079 continue;
3080
3081 if (tbl_idx >= IPA_MEM_PART(v6_modem_rt_index_lo) &&
3082 tbl_idx <= IPA_MEM_PART(v6_modem_rt_index_hi))
3083 continue;
3084
3085 if (ipa3_set_rt_tuple_mask(tbl_idx, &tuple)) {
3086 IPAERR("failed to setup tbl %d rt tuple\n", tbl_idx);
3087 return -EFAULT;
3088 }
3089 }
3090
3091 return 0;
3092}
3093
3094static int ipa3_setup_apps_pipes(void)
3095{
3096 struct ipa_sys_connect_params sys_in;
3097 int result = 0;
3098
3099 if (ipa3_ctx->gsi_ch20_wa) {
3100 IPADBG("Allocating GSI physical channel 20\n");
3101 result = ipa_gsi_ch20_wa();
3102 if (result) {
3103 IPAERR("ipa_gsi_ch20_wa failed %d\n", result);
Ghanim Fodic6b67492017-03-15 14:19:56 +02003104 goto fail_ch20_wa;
Amir Levy9659e592016-10-27 18:08:27 +03003105 }
3106 }
3107
Skylar Changd407e592017-03-30 11:25:30 -07003108 /* allocate the common PROD event ring */
3109 if (ipa3_alloc_common_event_ring()) {
3110 IPAERR("ipa3_alloc_common_event_ring failed.\n");
3111 result = -EPERM;
3112 goto fail_ch20_wa;
3113 }
3114
Amir Levy9659e592016-10-27 18:08:27 +03003115 /* CMD OUT (AP->IPA) */
3116 memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
3117 sys_in.client = IPA_CLIENT_APPS_CMD_PROD;
3118 sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
3119 sys_in.ipa_ep_cfg.mode.mode = IPA_DMA;
3120 sys_in.ipa_ep_cfg.mode.dst = IPA_CLIENT_APPS_LAN_CONS;
3121 if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_cmd)) {
Ghanim Fodic6b67492017-03-15 14:19:56 +02003122 IPAERR(":setup sys pipe (APPS_CMD_PROD) failed.\n");
Amir Levy9659e592016-10-27 18:08:27 +03003123 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003124 goto fail_ch20_wa;
Amir Levy9659e592016-10-27 18:08:27 +03003125 }
3126 IPADBG("Apps to IPA cmd pipe is connected\n");
3127
3128 ipa3_ctx->ctrl->ipa_init_sram();
3129 IPADBG("SRAM initialized\n");
3130
3131 ipa3_ctx->ctrl->ipa_init_hdr();
3132 IPADBG("HDR initialized\n");
3133
3134 ipa3_ctx->ctrl->ipa_init_rt4();
3135 IPADBG("V4 RT initialized\n");
3136
3137 ipa3_ctx->ctrl->ipa_init_rt6();
3138 IPADBG("V6 RT initialized\n");
3139
3140 ipa3_ctx->ctrl->ipa_init_flt4();
3141 IPADBG("V4 FLT initialized\n");
3142
3143 ipa3_ctx->ctrl->ipa_init_flt6();
3144 IPADBG("V6 FLT initialized\n");
3145
3146 if (ipa3_setup_flt_hash_tuple()) {
3147 IPAERR(":fail to configure flt hash tuple\n");
3148 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003149 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003150 }
3151 IPADBG("flt hash tuple is configured\n");
3152
3153 if (ipa3_setup_rt_hash_tuple()) {
3154 IPAERR(":fail to configure rt hash tuple\n");
3155 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003156 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003157 }
3158 IPADBG("rt hash tuple is configured\n");
3159
3160 if (ipa3_setup_exception_path()) {
3161 IPAERR(":fail to setup excp path\n");
3162 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003163 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003164 }
3165 IPADBG("Exception path was successfully set");
3166
3167 if (ipa3_setup_dflt_rt_tables()) {
3168 IPAERR(":fail to setup dflt routes\n");
3169 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003170 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003171 }
3172 IPADBG("default routing was set\n");
3173
Ghanim Fodic6b67492017-03-15 14:19:56 +02003174 /* LAN IN (IPA->AP) */
Amir Levy9659e592016-10-27 18:08:27 +03003175 memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
3176 sys_in.client = IPA_CLIENT_APPS_LAN_CONS;
3177 sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
3178 sys_in.notify = ipa3_lan_rx_cb;
3179 sys_in.priv = NULL;
3180 sys_in.ipa_ep_cfg.hdr.hdr_len = IPA_LAN_RX_HEADER_LENGTH;
3181 sys_in.ipa_ep_cfg.hdr_ext.hdr_little_endian = false;
3182 sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid = true;
3183 sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad = IPA_HDR_PAD;
3184 sys_in.ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = false;
3185 sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 0;
3186 sys_in.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2;
3187 sys_in.ipa_ep_cfg.cfg.cs_offload_en = IPA_ENABLE_CS_OFFLOAD_DL;
3188
3189 /**
3190 * ipa_lan_rx_cb() intended to notify the source EP about packet
3191 * being received on the LAN_CONS via calling the source EP call-back.
3192 * There could be a race condition with calling this call-back. Other
3193 * thread may nullify it - e.g. on EP disconnect.
3194 * This lock intended to protect the access to the source EP call-back
3195 */
3196 spin_lock_init(&ipa3_ctx->disconnect_lock);
3197 if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_data_in)) {
Ghanim Fodic6b67492017-03-15 14:19:56 +02003198 IPAERR(":setup sys pipe (LAN_CONS) failed.\n");
Amir Levy9659e592016-10-27 18:08:27 +03003199 result = -EPERM;
Ghanim Fodic6b67492017-03-15 14:19:56 +02003200 goto fail_flt_hash_tuple;
Amir Levy9659e592016-10-27 18:08:27 +03003201 }
3202
Ghanim Fodic6b67492017-03-15 14:19:56 +02003203 /* LAN OUT (AP->IPA) */
Amir Levy54fe4d32017-03-16 11:21:49 +02003204 if (!ipa3_ctx->ipa_config_is_mhi) {
3205 memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
3206 sys_in.client = IPA_CLIENT_APPS_LAN_PROD;
3207 sys_in.desc_fifo_sz = IPA_SYS_TX_DATA_DESC_FIFO_SZ;
3208 sys_in.ipa_ep_cfg.mode.mode = IPA_BASIC;
3209 if (ipa3_setup_sys_pipe(&sys_in,
3210 &ipa3_ctx->clnt_hdl_data_out)) {
3211 IPAERR(":setup sys pipe (LAN_PROD) failed.\n");
3212 result = -EPERM;
3213 goto fail_lan_data_out;
3214 }
Amir Levy9659e592016-10-27 18:08:27 +03003215 }
3216
3217 return 0;
3218
Ghanim Fodic6b67492017-03-15 14:19:56 +02003219fail_lan_data_out:
Amir Levy9659e592016-10-27 18:08:27 +03003220 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_in);
Ghanim Fodic6b67492017-03-15 14:19:56 +02003221fail_flt_hash_tuple:
Amir Levy9659e592016-10-27 18:08:27 +03003222 if (ipa3_ctx->dflt_v6_rt_rule_hdl)
3223 __ipa3_del_rt_rule(ipa3_ctx->dflt_v6_rt_rule_hdl);
3224 if (ipa3_ctx->dflt_v4_rt_rule_hdl)
3225 __ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl);
3226 if (ipa3_ctx->excp_hdr_hdl)
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02003227 __ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03003228 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
Ghanim Fodic6b67492017-03-15 14:19:56 +02003229fail_ch20_wa:
Amir Levy9659e592016-10-27 18:08:27 +03003230 return result;
3231}
3232
3233static void ipa3_teardown_apps_pipes(void)
3234{
Amir Levy54fe4d32017-03-16 11:21:49 +02003235 if (!ipa3_ctx->ipa_config_is_mhi)
3236 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_out);
Amir Levy9659e592016-10-27 18:08:27 +03003237 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_in);
3238 __ipa3_del_rt_rule(ipa3_ctx->dflt_v6_rt_rule_hdl);
3239 __ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl);
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02003240 __ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03003241 ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
3242}
3243
3244#ifdef CONFIG_COMPAT
Amir Levy479cfdd2017-10-26 12:23:14 +03003245
3246static long compat_ipa3_nat_ipv6ct_alloc_table(unsigned long arg,
3247 int (alloc_func)(struct ipa_ioc_nat_ipv6ct_table_alloc *))
3248{
3249 long retval;
3250 struct ipa_ioc_nat_ipv6ct_table_alloc32 table_alloc32;
3251 struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc;
3252
3253 retval = copy_from_user(&table_alloc32, (const void __user *)arg,
3254 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32));
3255 if (retval)
3256 return retval;
3257
3258 table_alloc.size = (size_t)table_alloc32.size;
3259 table_alloc.offset = (off_t)table_alloc32.offset;
3260
3261 retval = alloc_func(&table_alloc);
3262 if (retval)
3263 return retval;
3264
3265 if (table_alloc.offset) {
3266 table_alloc32.offset = (compat_off_t)table_alloc.offset;
3267 retval = copy_to_user((void __user *)arg, &table_alloc32,
3268 sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32));
3269 }
3270
3271 return retval;
3272}
3273
Amir Levy9659e592016-10-27 18:08:27 +03003274long compat_ipa3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
3275{
Amir Levy479cfdd2017-10-26 12:23:14 +03003276 long retval = 0;
Amir Levy9659e592016-10-27 18:08:27 +03003277 struct ipa3_ioc_nat_alloc_mem32 nat_mem32;
3278 struct ipa_ioc_nat_alloc_mem nat_mem;
3279
3280 switch (cmd) {
3281 case IPA_IOC_ADD_HDR32:
3282 cmd = IPA_IOC_ADD_HDR;
3283 break;
3284 case IPA_IOC_DEL_HDR32:
3285 cmd = IPA_IOC_DEL_HDR;
3286 break;
3287 case IPA_IOC_ADD_RT_RULE32:
3288 cmd = IPA_IOC_ADD_RT_RULE;
3289 break;
3290 case IPA_IOC_DEL_RT_RULE32:
3291 cmd = IPA_IOC_DEL_RT_RULE;
3292 break;
3293 case IPA_IOC_ADD_FLT_RULE32:
3294 cmd = IPA_IOC_ADD_FLT_RULE;
3295 break;
3296 case IPA_IOC_DEL_FLT_RULE32:
3297 cmd = IPA_IOC_DEL_FLT_RULE;
3298 break;
3299 case IPA_IOC_GET_RT_TBL32:
3300 cmd = IPA_IOC_GET_RT_TBL;
3301 break;
3302 case IPA_IOC_COPY_HDR32:
3303 cmd = IPA_IOC_COPY_HDR;
3304 break;
3305 case IPA_IOC_QUERY_INTF32:
3306 cmd = IPA_IOC_QUERY_INTF;
3307 break;
3308 case IPA_IOC_QUERY_INTF_TX_PROPS32:
3309 cmd = IPA_IOC_QUERY_INTF_TX_PROPS;
3310 break;
3311 case IPA_IOC_QUERY_INTF_RX_PROPS32:
3312 cmd = IPA_IOC_QUERY_INTF_RX_PROPS;
3313 break;
3314 case IPA_IOC_QUERY_INTF_EXT_PROPS32:
3315 cmd = IPA_IOC_QUERY_INTF_EXT_PROPS;
3316 break;
3317 case IPA_IOC_GET_HDR32:
3318 cmd = IPA_IOC_GET_HDR;
3319 break;
3320 case IPA_IOC_ALLOC_NAT_MEM32:
Amir Levy479cfdd2017-10-26 12:23:14 +03003321 retval = copy_from_user(&nat_mem32, (const void __user *)arg,
3322 sizeof(struct ipa3_ioc_nat_alloc_mem32));
3323 if (retval)
3324 return retval;
Amir Levy9659e592016-10-27 18:08:27 +03003325 memcpy(nat_mem.dev_name, nat_mem32.dev_name,
3326 IPA_RESOURCE_NAME_MAX);
3327 nat_mem.size = (size_t)nat_mem32.size;
3328 nat_mem.offset = (off_t)nat_mem32.offset;
3329
3330 /* null terminate the string */
3331 nat_mem.dev_name[IPA_RESOURCE_NAME_MAX - 1] = '\0';
3332
Amir Levy479cfdd2017-10-26 12:23:14 +03003333 retval = ipa3_allocate_nat_device(&nat_mem);
3334 if (retval)
3335 return retval;
Amir Levy9659e592016-10-27 18:08:27 +03003336 nat_mem32.offset = (compat_off_t)nat_mem.offset;
Amir Levy479cfdd2017-10-26 12:23:14 +03003337 retval = copy_to_user((void __user *)arg, &nat_mem32,
3338 sizeof(struct ipa3_ioc_nat_alloc_mem32));
Amir Levy9659e592016-10-27 18:08:27 +03003339 return retval;
Amir Levy479cfdd2017-10-26 12:23:14 +03003340 case IPA_IOC_ALLOC_NAT_TABLE32:
3341 return compat_ipa3_nat_ipv6ct_alloc_table(arg,
3342 ipa3_allocate_nat_table);
3343 case IPA_IOC_ALLOC_IPV6CT_TABLE32:
3344 return compat_ipa3_nat_ipv6ct_alloc_table(arg,
3345 ipa3_allocate_ipv6ct_table);
Amir Levy9659e592016-10-27 18:08:27 +03003346 case IPA_IOC_V4_INIT_NAT32:
3347 cmd = IPA_IOC_V4_INIT_NAT;
3348 break;
Amir Levy479cfdd2017-10-26 12:23:14 +03003349 case IPA_IOC_INIT_IPV6CT_TABLE32:
3350 cmd = IPA_IOC_INIT_IPV6CT_TABLE;
3351 break;
3352 case IPA_IOC_TABLE_DMA_CMD32:
3353 cmd = IPA_IOC_TABLE_DMA_CMD;
Amir Levy9659e592016-10-27 18:08:27 +03003354 break;
3355 case IPA_IOC_V4_DEL_NAT32:
3356 cmd = IPA_IOC_V4_DEL_NAT;
3357 break;
Amir Levy479cfdd2017-10-26 12:23:14 +03003358 case IPA_IOC_DEL_NAT_TABLE32:
3359 cmd = IPA_IOC_DEL_NAT_TABLE;
3360 break;
3361 case IPA_IOC_DEL_IPV6CT_TABLE32:
3362 cmd = IPA_IOC_DEL_IPV6CT_TABLE;
3363 break;
3364 case IPA_IOC_NAT_MODIFY_PDN32:
3365 cmd = IPA_IOC_NAT_MODIFY_PDN;
3366 break;
Amir Levy9659e592016-10-27 18:08:27 +03003367 case IPA_IOC_GET_NAT_OFFSET32:
3368 cmd = IPA_IOC_GET_NAT_OFFSET;
3369 break;
3370 case IPA_IOC_PULL_MSG32:
3371 cmd = IPA_IOC_PULL_MSG;
3372 break;
3373 case IPA_IOC_RM_ADD_DEPENDENCY32:
3374 cmd = IPA_IOC_RM_ADD_DEPENDENCY;
3375 break;
3376 case IPA_IOC_RM_DEL_DEPENDENCY32:
3377 cmd = IPA_IOC_RM_DEL_DEPENDENCY;
3378 break;
3379 case IPA_IOC_GENERATE_FLT_EQ32:
3380 cmd = IPA_IOC_GENERATE_FLT_EQ;
3381 break;
3382 case IPA_IOC_QUERY_RT_TBL_INDEX32:
3383 cmd = IPA_IOC_QUERY_RT_TBL_INDEX;
3384 break;
3385 case IPA_IOC_WRITE_QMAPID32:
3386 cmd = IPA_IOC_WRITE_QMAPID;
3387 break;
3388 case IPA_IOC_MDFY_FLT_RULE32:
3389 cmd = IPA_IOC_MDFY_FLT_RULE;
3390 break;
3391 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD32:
3392 cmd = IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD;
3393 break;
3394 case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL32:
3395 cmd = IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL;
3396 break;
3397 case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED32:
3398 cmd = IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED;
3399 break;
3400 case IPA_IOC_MDFY_RT_RULE32:
3401 cmd = IPA_IOC_MDFY_RT_RULE;
3402 break;
3403 case IPA_IOC_COMMIT_HDR:
3404 case IPA_IOC_RESET_HDR:
3405 case IPA_IOC_COMMIT_RT:
3406 case IPA_IOC_RESET_RT:
3407 case IPA_IOC_COMMIT_FLT:
3408 case IPA_IOC_RESET_FLT:
3409 case IPA_IOC_DUMP:
3410 case IPA_IOC_PUT_RT_TBL:
3411 case IPA_IOC_PUT_HDR:
3412 case IPA_IOC_SET_FLT:
3413 case IPA_IOC_QUERY_EP_MAPPING:
3414 break;
3415 default:
3416 return -ENOIOCTLCMD;
3417 }
3418 return ipa3_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
3419}
3420#endif
3421
3422static ssize_t ipa3_write(struct file *file, const char __user *buf,
3423 size_t count, loff_t *ppos);
3424
3425static const struct file_operations ipa3_drv_fops = {
3426 .owner = THIS_MODULE,
3427 .open = ipa3_open,
3428 .read = ipa3_read,
3429 .write = ipa3_write,
3430 .unlocked_ioctl = ipa3_ioctl,
3431#ifdef CONFIG_COMPAT
3432 .compat_ioctl = compat_ipa3_ioctl,
3433#endif
3434};
3435
3436static int ipa3_get_clks(struct device *dev)
3437{
Ghanim Fodi6a831342017-03-07 18:19:15 +02003438 if (ipa3_res.use_bw_vote) {
3439 IPADBG("Vote IPA clock by bw voting via bus scaling driver\n");
3440 ipa3_clk = NULL;
3441 return 0;
3442 }
3443
Amir Levy9659e592016-10-27 18:08:27 +03003444 ipa3_clk = clk_get(dev, "core_clk");
3445 if (IS_ERR(ipa3_clk)) {
3446 if (ipa3_clk != ERR_PTR(-EPROBE_DEFER))
3447 IPAERR("fail to get ipa clk\n");
3448 return PTR_ERR(ipa3_clk);
3449 }
3450 return 0;
3451}
3452
3453/**
3454 * _ipa_enable_clks_v3_0() - Enable IPA clocks.
3455 */
3456void _ipa_enable_clks_v3_0(void)
3457{
Ghanim Fodi6a831342017-03-07 18:19:15 +02003458 IPADBG_LOW("curr_ipa_clk_rate=%d", ipa3_ctx->curr_ipa_clk_rate);
Amir Levy9659e592016-10-27 18:08:27 +03003459 if (ipa3_clk) {
Ghanim Fodi6a831342017-03-07 18:19:15 +02003460 IPADBG_LOW("enabling gcc_ipa_clk\n");
Amir Levy9659e592016-10-27 18:08:27 +03003461 clk_prepare(ipa3_clk);
3462 clk_enable(ipa3_clk);
Amir Levy9659e592016-10-27 18:08:27 +03003463 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
Amir Levy9659e592016-10-27 18:08:27 +03003464 }
3465
Ghanim Fodi6a831342017-03-07 18:19:15 +02003466 ipa3_uc_notify_clk_state(true);
Amir Levy9659e592016-10-27 18:08:27 +03003467}
3468
3469static unsigned int ipa3_get_bus_vote(void)
3470{
3471 unsigned int idx = 1;
3472
Skylar Chang448d8b82017-08-08 17:30:32 -07003473 if (ipa3_ctx->curr_ipa_clk_rate == ipa3_ctx->ctrl->ipa_clk_rate_svs2) {
Amir Levy9659e592016-10-27 18:08:27 +03003474 idx = 1;
3475 } else if (ipa3_ctx->curr_ipa_clk_rate ==
Skylar Chang448d8b82017-08-08 17:30:32 -07003476 ipa3_ctx->ctrl->ipa_clk_rate_svs) {
3477 idx = 2;
3478 } else if (ipa3_ctx->curr_ipa_clk_rate ==
3479 ipa3_ctx->ctrl->ipa_clk_rate_nominal) {
3480 idx = 3;
Amir Levy9659e592016-10-27 18:08:27 +03003481 } else if (ipa3_ctx->curr_ipa_clk_rate ==
3482 ipa3_ctx->ctrl->ipa_clk_rate_turbo) {
3483 idx = ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases - 1;
3484 } else {
3485 WARN_ON(1);
3486 }
Amir Levy9659e592016-10-27 18:08:27 +03003487 IPADBG("curr %d idx %d\n", ipa3_ctx->curr_ipa_clk_rate, idx);
3488
3489 return idx;
3490}
3491
3492/**
3493* ipa3_enable_clks() - Turn on IPA clocks
3494*
3495* Return codes:
3496* None
3497*/
3498void ipa3_enable_clks(void)
3499{
3500 IPADBG("enabling IPA clocks and bus voting\n");
3501
Ghanim Fodi6a831342017-03-07 18:19:15 +02003502 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
3503 ipa3_get_bus_vote()))
3504 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03003505
Ghanim Fodi6a831342017-03-07 18:19:15 +02003506 ipa3_ctx->ctrl->ipa3_enable_clks();
Amir Levy9659e592016-10-27 18:08:27 +03003507}
3508
3509
3510/**
3511 * _ipa_disable_clks_v3_0() - Disable IPA clocks.
3512 */
3513void _ipa_disable_clks_v3_0(void)
3514{
Amir Levy9659e592016-10-27 18:08:27 +03003515 ipa3_suspend_apps_pipes(true);
3516 ipa3_uc_notify_clk_state(false);
Ghanim Fodi6a831342017-03-07 18:19:15 +02003517 if (ipa3_clk) {
3518 IPADBG_LOW("disabling gcc_ipa_clk\n");
Amir Levy9659e592016-10-27 18:08:27 +03003519 clk_disable_unprepare(ipa3_clk);
Ghanim Fodi6a831342017-03-07 18:19:15 +02003520 }
Amir Levy9659e592016-10-27 18:08:27 +03003521}
3522
3523/**
3524* ipa3_disable_clks() - Turn off IPA clocks
3525*
3526* Return codes:
3527* None
3528*/
3529void ipa3_disable_clks(void)
3530{
3531 IPADBG("disabling IPA clocks and bus voting\n");
3532
3533 ipa3_ctx->ctrl->ipa3_disable_clks();
3534
Ghanim Fodi6a831342017-03-07 18:19:15 +02003535 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl, 0))
3536 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03003537}
3538
3539/**
3540 * ipa3_start_tag_process() - Send TAG packet and wait for it to come back
3541 *
3542 * This function is called prior to clock gating when active client counter
3543 * is 1. TAG process ensures that there are no packets inside IPA HW that
Amir Levya59ed3f2017-03-05 17:30:55 +02003544 * were not submitted to the IPA client via the transport. During TAG process
3545 * all aggregation frames are (force) closed.
Amir Levy9659e592016-10-27 18:08:27 +03003546 *
3547 * Return codes:
3548 * None
3549 */
3550static void ipa3_start_tag_process(struct work_struct *work)
3551{
3552 int res;
3553
3554 IPADBG("starting TAG process\n");
3555 /* close aggregation frames on all pipes */
3556 res = ipa3_tag_aggr_force_close(-1);
3557 if (res)
3558 IPAERR("ipa3_tag_aggr_force_close failed %d\n", res);
3559 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("TAG_PROCESS");
3560
3561 IPADBG("TAG process done\n");
3562}
3563
3564/**
3565* ipa3_active_clients_log_mod() - Log a modification in the active clients
3566* reference count
3567*
3568* This method logs any modification in the active clients reference count:
3569* It logs the modification in the circular history buffer
3570* It logs the modification in the hash table - looking for an entry,
3571* creating one if needed and deleting one if needed.
3572*
3573* @id: ipa3_active client logging info struct to hold the log information
3574* @inc: a boolean variable to indicate whether the modification is an increase
3575* or decrease
3576* @int_ctx: a boolean variable to indicate whether this call is being made from
3577* an interrupt context and therefore should allocate GFP_ATOMIC memory
3578*
3579* Method process:
3580* - Hash the unique identifier string
3581* - Find the hash in the table
3582* 1)If found, increase or decrease the reference count
3583* 2)If not found, allocate a new hash table entry struct and initialize it
3584* - Remove and deallocate unneeded data structure
3585* - Log the call in the circular history buffer (unless it is a simple call)
3586*/
3587void ipa3_active_clients_log_mod(struct ipa_active_client_logging_info *id,
3588 bool inc, bool int_ctx)
3589{
3590 char temp_str[IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN];
3591 unsigned long long t;
3592 unsigned long nanosec_rem;
3593 struct ipa3_active_client_htable_entry *hentry;
3594 struct ipa3_active_client_htable_entry *hfound;
3595 u32 hkey;
3596 char str_to_hash[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
Skylar Chang69ae50e2017-07-31 13:13:29 -07003597 unsigned long flags;
Amir Levy9659e592016-10-27 18:08:27 +03003598
Skylar Chang69ae50e2017-07-31 13:13:29 -07003599 spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients_logging.lock, flags);
3600 int_ctx = true;
Amir Levy9659e592016-10-27 18:08:27 +03003601 hfound = NULL;
3602 memset(str_to_hash, 0, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
3603 strlcpy(str_to_hash, id->id_string, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
Amir Levyd9f51132016-11-14 16:55:35 +02003604 hkey = jhash(str_to_hash, IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN,
Amir Levy9659e592016-10-27 18:08:27 +03003605 0);
3606 hash_for_each_possible(ipa3_ctx->ipa3_active_clients_logging.htable,
3607 hentry, list, hkey) {
3608 if (!strcmp(hentry->id_string, id->id_string)) {
3609 hentry->count = hentry->count + (inc ? 1 : -1);
3610 hfound = hentry;
3611 }
3612 }
3613 if (hfound == NULL) {
3614 hentry = NULL;
3615 hentry = kzalloc(sizeof(
3616 struct ipa3_active_client_htable_entry),
3617 int_ctx ? GFP_ATOMIC : GFP_KERNEL);
3618 if (hentry == NULL) {
3619 IPAERR("failed allocating active clients hash entry");
Skylar Chang69ae50e2017-07-31 13:13:29 -07003620 spin_unlock_irqrestore(
3621 &ipa3_ctx->ipa3_active_clients_logging.lock,
3622 flags);
Amir Levy9659e592016-10-27 18:08:27 +03003623 return;
3624 }
3625 hentry->type = id->type;
3626 strlcpy(hentry->id_string, id->id_string,
3627 IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN);
3628 INIT_HLIST_NODE(&hentry->list);
3629 hentry->count = inc ? 1 : -1;
3630 hash_add(ipa3_ctx->ipa3_active_clients_logging.htable,
3631 &hentry->list, hkey);
3632 } else if (hfound->count == 0) {
3633 hash_del(&hfound->list);
3634 kfree(hfound);
3635 }
3636
3637 if (id->type != SIMPLE) {
3638 t = local_clock();
3639 nanosec_rem = do_div(t, 1000000000) / 1000;
3640 snprintf(temp_str, IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN,
3641 inc ? "[%5lu.%06lu] ^ %s, %s: %d" :
3642 "[%5lu.%06lu] v %s, %s: %d",
3643 (unsigned long)t, nanosec_rem,
3644 id->id_string, id->file, id->line);
3645 ipa3_active_clients_log_insert(temp_str);
3646 }
Skylar Chang69ae50e2017-07-31 13:13:29 -07003647 spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients_logging.lock,
3648 flags);
Amir Levy9659e592016-10-27 18:08:27 +03003649}
3650
3651void ipa3_active_clients_log_dec(struct ipa_active_client_logging_info *id,
3652 bool int_ctx)
3653{
3654 ipa3_active_clients_log_mod(id, false, int_ctx);
3655}
3656
3657void ipa3_active_clients_log_inc(struct ipa_active_client_logging_info *id,
3658 bool int_ctx)
3659{
3660 ipa3_active_clients_log_mod(id, true, int_ctx);
3661}
3662
3663/**
3664* ipa3_inc_client_enable_clks() - Increase active clients counter, and
3665* enable ipa clocks if necessary
3666*
3667* Return codes:
3668* None
3669*/
3670void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id)
3671{
Skylar Chang242952b2017-07-20 15:04:05 -07003672 int ret;
3673
Amir Levy9659e592016-10-27 18:08:27 +03003674 ipa3_active_clients_log_inc(id, false);
Skylar Chang242952b2017-07-20 15:04:05 -07003675 ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
3676 if (ret) {
3677 IPADBG_LOW("active clients = %d\n",
3678 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3679 return;
3680 }
3681
3682 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
3683
3684 /* somebody might voted to clocks meanwhile */
3685 ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
3686 if (ret) {
3687 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
3688 IPADBG_LOW("active clients = %d\n",
3689 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3690 return;
3691 }
3692
3693 ipa3_enable_clks();
3694 atomic_inc(&ipa3_ctx->ipa3_active_clients.cnt);
3695 IPADBG_LOW("active clients = %d\n",
3696 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3697 ipa3_suspend_apps_pipes(false);
3698 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03003699}
3700
3701/**
3702* ipa3_inc_client_enable_clks_no_block() - Only increment the number of active
3703* clients if no asynchronous actions should be done. Asynchronous actions are
3704* locking a mutex and waking up IPA HW.
3705*
3706* Return codes: 0 for success
3707* -EPERM if an asynchronous action should have been done
3708*/
3709int ipa3_inc_client_enable_clks_no_block(struct ipa_active_client_logging_info
3710 *id)
3711{
Skylar Chang242952b2017-07-20 15:04:05 -07003712 int ret;
Amir Levy9659e592016-10-27 18:08:27 +03003713
Skylar Chang242952b2017-07-20 15:04:05 -07003714 ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
3715 if (ret) {
3716 ipa3_active_clients_log_inc(id, true);
3717 IPADBG_LOW("active clients = %d\n",
3718 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3719 return 0;
Amir Levy9659e592016-10-27 18:08:27 +03003720 }
Amir Levy9659e592016-10-27 18:08:27 +03003721
Skylar Chang242952b2017-07-20 15:04:05 -07003722 return -EPERM;
3723}
3724
3725static void __ipa3_dec_client_disable_clks(void)
3726{
3727 int ret;
3728
3729 if (!atomic_read(&ipa3_ctx->ipa3_active_clients.cnt)) {
3730 IPAERR("trying to disable clocks with refcnt is 0!\n");
3731 ipa_assert();
3732 return;
3733 }
3734
3735 ret = atomic_add_unless(&ipa3_ctx->ipa3_active_clients.cnt, -1, 1);
3736 if (ret)
3737 goto bail;
3738
3739 /* seems like this is the only client holding the clocks */
3740 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
3741 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) == 1 &&
3742 ipa3_ctx->tag_process_before_gating) {
3743 ipa3_ctx->tag_process_before_gating = false;
3744 /*
3745 * When TAG process ends, active clients will be
3746 * decreased
3747 */
3748 queue_work(ipa3_ctx->power_mgmt_wq, &ipa3_tag_work);
3749 goto unlock_mutex;
3750 }
3751
3752 /* a different context might increase the clock reference meanwhile */
3753 ret = atomic_sub_return(1, &ipa3_ctx->ipa3_active_clients.cnt);
3754 if (ret > 0)
3755 goto unlock_mutex;
3756 ipa3_disable_clks();
3757
3758unlock_mutex:
3759 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
3760bail:
3761 IPADBG_LOW("active clients = %d\n",
3762 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
Amir Levy9659e592016-10-27 18:08:27 +03003763}
3764
3765/**
3766 * ipa3_dec_client_disable_clks() - Decrease active clients counter
3767 *
3768 * In case that there are no active clients this function also starts
3769 * TAG process. When TAG progress ends ipa clocks will be gated.
3770 * start_tag_process_again flag is set during this function to signal TAG
3771 * process to start again as there was another client that may send data to ipa
3772 *
3773 * Return codes:
3774 * None
3775 */
3776void ipa3_dec_client_disable_clks(struct ipa_active_client_logging_info *id)
3777{
Amir Levy9659e592016-10-27 18:08:27 +03003778 ipa3_active_clients_log_dec(id, false);
Skylar Chang242952b2017-07-20 15:04:05 -07003779 __ipa3_dec_client_disable_clks();
3780}
3781
3782static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work)
3783{
3784 __ipa3_dec_client_disable_clks();
3785}
3786
3787/**
3788 * ipa3_dec_client_disable_clks_no_block() - Decrease active clients counter
3789 * if possible without blocking. If this is the last client then the desrease
3790 * will happen from work queue context.
3791 *
3792 * Return codes:
3793 * None
3794 */
3795void ipa3_dec_client_disable_clks_no_block(
3796 struct ipa_active_client_logging_info *id)
3797{
3798 int ret;
3799
3800 ipa3_active_clients_log_dec(id, true);
3801 ret = atomic_add_unless(&ipa3_ctx->ipa3_active_clients.cnt, -1, 1);
3802 if (ret) {
3803 IPADBG_LOW("active clients = %d\n",
3804 atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
3805 return;
Amir Levy9659e592016-10-27 18:08:27 +03003806 }
Skylar Chang242952b2017-07-20 15:04:05 -07003807
3808 /* seems like this is the only client holding the clocks */
3809 queue_work(ipa3_ctx->power_mgmt_wq,
3810 &ipa_dec_clients_disable_clks_on_wq_work);
Amir Levy9659e592016-10-27 18:08:27 +03003811}
3812
3813/**
3814* ipa3_inc_acquire_wakelock() - Increase active clients counter, and
3815* acquire wakelock if necessary
3816*
3817* Return codes:
3818* None
3819*/
3820void ipa3_inc_acquire_wakelock(void)
3821{
3822 unsigned long flags;
3823
3824 spin_lock_irqsave(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
3825 ipa3_ctx->wakelock_ref_cnt.cnt++;
3826 if (ipa3_ctx->wakelock_ref_cnt.cnt == 1)
3827 __pm_stay_awake(&ipa3_ctx->w_lock);
3828 IPADBG_LOW("active wakelock ref cnt = %d\n",
3829 ipa3_ctx->wakelock_ref_cnt.cnt);
3830 spin_unlock_irqrestore(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
3831}
3832
3833/**
3834 * ipa3_dec_release_wakelock() - Decrease active clients counter
3835 *
3836 * In case if the ref count is 0, release the wakelock.
3837 *
3838 * Return codes:
3839 * None
3840 */
3841void ipa3_dec_release_wakelock(void)
3842{
3843 unsigned long flags;
3844
3845 spin_lock_irqsave(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
3846 ipa3_ctx->wakelock_ref_cnt.cnt--;
3847 IPADBG_LOW("active wakelock ref cnt = %d\n",
3848 ipa3_ctx->wakelock_ref_cnt.cnt);
3849 if (ipa3_ctx->wakelock_ref_cnt.cnt == 0)
3850 __pm_relax(&ipa3_ctx->w_lock);
3851 spin_unlock_irqrestore(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
3852}
3853
Michael Adisumartac06df412017-09-19 10:10:35 -07003854int ipa3_set_clock_plan_from_pm(int idx)
3855{
3856 u32 clk_rate;
3857
3858 IPADBG_LOW("idx = %d\n", idx);
3859
3860 if (idx <= 0 || idx >= ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases) {
3861 IPAERR("bad voltage\n");
3862 return -EINVAL;
3863 }
3864
3865 if (idx == 1)
3866 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
3867 else if (idx == 2)
3868 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
3869 else if (idx == 3)
3870 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
3871 else {
3872 IPAERR("bad voltage\n");
3873 WARN_ON(1);
3874 return -EFAULT;
3875 }
3876
3877 if (clk_rate == ipa3_ctx->curr_ipa_clk_rate) {
3878 IPADBG_LOW("Same voltage\n");
3879 return 0;
3880 }
3881
3882 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
3883 ipa3_ctx->curr_ipa_clk_rate = clk_rate;
3884 ipa3_ctx->ipa3_active_clients.bus_vote_idx = idx;
3885 IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
3886 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) > 0) {
3887 if (ipa3_clk)
3888 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
3889 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
3890 ipa3_get_bus_vote()))
3891 WARN_ON(1);
3892 } else {
3893 IPADBG_LOW("clocks are gated, not setting rate\n");
3894 }
3895 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
3896 IPADBG_LOW("Done\n");
3897
3898 return 0;
3899}
3900
Amir Levy9659e592016-10-27 18:08:27 +03003901int ipa3_set_required_perf_profile(enum ipa_voltage_level floor_voltage,
3902 u32 bandwidth_mbps)
3903{
3904 enum ipa_voltage_level needed_voltage;
3905 u32 clk_rate;
3906
3907 IPADBG_LOW("floor_voltage=%d, bandwidth_mbps=%u",
3908 floor_voltage, bandwidth_mbps);
3909
3910 if (floor_voltage < IPA_VOLTAGE_UNSPECIFIED ||
3911 floor_voltage >= IPA_VOLTAGE_MAX) {
3912 IPAERR("bad voltage\n");
3913 return -EINVAL;
3914 }
3915
3916 if (ipa3_ctx->enable_clock_scaling) {
3917 IPADBG_LOW("Clock scaling is enabled\n");
3918 if (bandwidth_mbps >=
3919 ipa3_ctx->ctrl->clock_scaling_bw_threshold_turbo)
3920 needed_voltage = IPA_VOLTAGE_TURBO;
3921 else if (bandwidth_mbps >=
3922 ipa3_ctx->ctrl->clock_scaling_bw_threshold_nominal)
3923 needed_voltage = IPA_VOLTAGE_NOMINAL;
Skylar Chang448d8b82017-08-08 17:30:32 -07003924 else if (bandwidth_mbps >=
3925 ipa3_ctx->ctrl->clock_scaling_bw_threshold_svs)
Amir Levy9659e592016-10-27 18:08:27 +03003926 needed_voltage = IPA_VOLTAGE_SVS;
Skylar Chang448d8b82017-08-08 17:30:32 -07003927 else
3928 needed_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +03003929 } else {
3930 IPADBG_LOW("Clock scaling is disabled\n");
3931 needed_voltage = IPA_VOLTAGE_NOMINAL;
3932 }
3933
3934 needed_voltage = max(needed_voltage, floor_voltage);
3935 switch (needed_voltage) {
Skylar Chang448d8b82017-08-08 17:30:32 -07003936 case IPA_VOLTAGE_SVS2:
3937 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs2;
3938 break;
Amir Levy9659e592016-10-27 18:08:27 +03003939 case IPA_VOLTAGE_SVS:
3940 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
3941 break;
3942 case IPA_VOLTAGE_NOMINAL:
3943 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
3944 break;
3945 case IPA_VOLTAGE_TURBO:
3946 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
3947 break;
3948 default:
3949 IPAERR("bad voltage\n");
3950 WARN_ON(1);
3951 return -EFAULT;
3952 }
3953
3954 if (clk_rate == ipa3_ctx->curr_ipa_clk_rate) {
3955 IPADBG_LOW("Same voltage\n");
3956 return 0;
3957 }
3958
Skylar Chang242952b2017-07-20 15:04:05 -07003959 /* Hold the mutex to avoid race conditions with ipa3_enable_clocks() */
3960 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03003961 ipa3_ctx->curr_ipa_clk_rate = clk_rate;
3962 IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
Skylar Chang242952b2017-07-20 15:04:05 -07003963 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) > 0) {
Ghanim Fodi6a831342017-03-07 18:19:15 +02003964 if (ipa3_clk)
3965 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
3966 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
Skylar Chang242952b2017-07-20 15:04:05 -07003967 ipa3_get_bus_vote()))
Ghanim Fodi6a831342017-03-07 18:19:15 +02003968 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03003969 } else {
3970 IPADBG_LOW("clocks are gated, not setting rate\n");
3971 }
Skylar Chang242952b2017-07-20 15:04:05 -07003972 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03003973 IPADBG_LOW("Done\n");
Skylar Chang1cbe99c2017-05-01 13:44:03 -07003974
Amir Levy9659e592016-10-27 18:08:27 +03003975 return 0;
3976}
3977
Amir Levya59ed3f2017-03-05 17:30:55 +02003978static void ipa3_process_irq_schedule_rel(void)
Amir Levy9659e592016-10-27 18:08:27 +03003979{
3980 queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
Amir Levya59ed3f2017-03-05 17:30:55 +02003981 &ipa3_transport_release_resource_work,
Amir Levy9659e592016-10-27 18:08:27 +03003982 msecs_to_jiffies(IPA_TRANSPORT_PROD_TIMEOUT_MSEC));
3983}
3984
3985/**
3986* ipa3_suspend_handler() - Handles the suspend interrupt:
3987* wakes up the suspended peripheral by requesting its consumer
3988* @interrupt: Interrupt type
3989* @private_data: The client's private data
3990* @interrupt_data: Interrupt specific information data
3991*/
3992void ipa3_suspend_handler(enum ipa_irq_type interrupt,
3993 void *private_data,
3994 void *interrupt_data)
3995{
3996 enum ipa_rm_resource_name resource;
3997 u32 suspend_data =
3998 ((struct ipa_tx_suspend_irq_data *)interrupt_data)->endpoints;
3999 u32 bmsk = 1;
4000 u32 i = 0;
4001 int res;
4002 struct ipa_ep_cfg_holb holb_cfg;
Michael Adisumarta3e350812017-09-18 14:54:36 -07004003 u32 pipe_bitmask = 0;
Amir Levy9659e592016-10-27 18:08:27 +03004004
4005 IPADBG("interrupt=%d, interrupt_data=%u\n",
4006 interrupt, suspend_data);
4007 memset(&holb_cfg, 0, sizeof(holb_cfg));
4008 holb_cfg.tmr_val = 0;
4009
Michael Adisumarta3e350812017-09-18 14:54:36 -07004010 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++, bmsk = bmsk << 1) {
Amir Levy9659e592016-10-27 18:08:27 +03004011 if ((suspend_data & bmsk) && (ipa3_ctx->ep[i].valid)) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07004012 if (ipa3_ctx->use_ipa_pm) {
4013 pipe_bitmask |= bmsk;
4014 continue;
4015 }
Amir Levy9659e592016-10-27 18:08:27 +03004016 if (IPA_CLIENT_IS_APPS_CONS(ipa3_ctx->ep[i].client)) {
4017 /*
4018 * pipe will be unsuspended as part of
4019 * enabling IPA clocks
4020 */
Skylar Chang0d06bb12017-02-24 11:22:03 -08004021 mutex_lock(&ipa3_ctx->transport_pm.
4022 transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004023 if (!atomic_read(
4024 &ipa3_ctx->transport_pm.dec_clients)
4025 ) {
4026 IPA_ACTIVE_CLIENTS_INC_EP(
4027 ipa3_ctx->ep[i].client);
4028 IPADBG_LOW("Pipes un-suspended.\n");
4029 IPADBG_LOW("Enter poll mode.\n");
4030 atomic_set(
4031 &ipa3_ctx->transport_pm.dec_clients,
4032 1);
Skylar Chang9e3b6492017-11-07 09:49:48 -08004033 /*
4034 * acquire wake lock as long as suspend
4035 * vote is held
4036 */
4037 ipa3_inc_acquire_wakelock();
Amir Levya59ed3f2017-03-05 17:30:55 +02004038 ipa3_process_irq_schedule_rel();
Amir Levy9659e592016-10-27 18:08:27 +03004039 }
Skylar Chang0d06bb12017-02-24 11:22:03 -08004040 mutex_unlock(&ipa3_ctx->transport_pm.
4041 transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004042 } else {
4043 resource = ipa3_get_rm_resource_from_ep(i);
4044 res =
4045 ipa_rm_request_resource_with_timer(resource);
4046 if (res == -EPERM &&
4047 IPA_CLIENT_IS_CONS(
4048 ipa3_ctx->ep[i].client)) {
4049 holb_cfg.en = 1;
4050 res = ipa3_cfg_ep_holb_by_client(
4051 ipa3_ctx->ep[i].client, &holb_cfg);
4052 if (res) {
4053 IPAERR("holb en fail, stall\n");
4054 BUG();
4055 }
4056 }
4057 }
4058 }
Michael Adisumarta3e350812017-09-18 14:54:36 -07004059 }
4060 if (ipa3_ctx->use_ipa_pm) {
4061 res = ipa_pm_handle_suspend(pipe_bitmask);
4062 if (res) {
4063 IPAERR("ipa_pm_handle_suspend failed %d\n", res);
4064 return;
4065 }
Amir Levy9659e592016-10-27 18:08:27 +03004066 }
4067}
4068
4069/**
4070* ipa3_restore_suspend_handler() - restores the original suspend IRQ handler
4071* as it was registered in the IPA init sequence.
4072* Return codes:
4073* 0: success
4074* -EPERM: failed to remove current handler or failed to add original handler
4075*/
4076int ipa3_restore_suspend_handler(void)
4077{
4078 int result = 0;
4079
4080 result = ipa3_remove_interrupt_handler(IPA_TX_SUSPEND_IRQ);
4081 if (result) {
4082 IPAERR("remove handler for suspend interrupt failed\n");
4083 return -EPERM;
4084 }
4085
4086 result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
4087 ipa3_suspend_handler, false, NULL);
4088 if (result) {
4089 IPAERR("register handler for suspend interrupt failed\n");
4090 result = -EPERM;
4091 }
4092
4093 IPADBG("suspend handler successfully restored\n");
4094
4095 return result;
4096}
4097
4098static int ipa3_apps_cons_release_resource(void)
4099{
4100 return 0;
4101}
4102
4103static int ipa3_apps_cons_request_resource(void)
4104{
4105 return 0;
4106}
4107
Amir Levya59ed3f2017-03-05 17:30:55 +02004108static void ipa3_transport_release_resource(struct work_struct *work)
Amir Levy9659e592016-10-27 18:08:27 +03004109{
Sridhar Ancha99b505b2016-04-21 23:11:10 +05304110 mutex_lock(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004111 /* check whether still need to decrease client usage */
4112 if (atomic_read(&ipa3_ctx->transport_pm.dec_clients)) {
4113 if (atomic_read(&ipa3_ctx->transport_pm.eot_activity)) {
4114 IPADBG("EOT pending Re-scheduling\n");
Amir Levya59ed3f2017-03-05 17:30:55 +02004115 ipa3_process_irq_schedule_rel();
Amir Levy9659e592016-10-27 18:08:27 +03004116 } else {
4117 atomic_set(&ipa3_ctx->transport_pm.dec_clients, 0);
Skylar Chang9e3b6492017-11-07 09:49:48 -08004118 ipa3_dec_release_wakelock();
Amir Levya59ed3f2017-03-05 17:30:55 +02004119 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("TRANSPORT_RESOURCE");
Amir Levy9659e592016-10-27 18:08:27 +03004120 }
4121 }
4122 atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
Sridhar Ancha99b505b2016-04-21 23:11:10 +05304123 mutex_unlock(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004124}
4125
4126int ipa3_create_apps_resource(void)
4127{
4128 struct ipa_rm_create_params apps_cons_create_params;
4129 struct ipa_rm_perf_profile profile;
4130 int result = 0;
4131
4132 memset(&apps_cons_create_params, 0,
4133 sizeof(apps_cons_create_params));
4134 apps_cons_create_params.name = IPA_RM_RESOURCE_APPS_CONS;
4135 apps_cons_create_params.request_resource =
4136 ipa3_apps_cons_request_resource;
4137 apps_cons_create_params.release_resource =
4138 ipa3_apps_cons_release_resource;
4139 result = ipa_rm_create_resource(&apps_cons_create_params);
4140 if (result) {
4141 IPAERR("ipa_rm_create_resource failed\n");
4142 return result;
4143 }
4144
4145 profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
4146 ipa_rm_set_perf_profile(IPA_RM_RESOURCE_APPS_CONS, &profile);
4147
4148 return result;
4149}
4150
4151/**
4152 * ipa3_init_interrupts() - Register to IPA IRQs
4153 *
4154 * Return codes: 0 in success, negative in failure
4155 *
4156 */
4157int ipa3_init_interrupts(void)
4158{
4159 int result;
4160
4161 /*register IPA IRQ handler*/
4162 result = ipa3_interrupts_init(ipa3_res.ipa_irq, 0,
4163 master_dev);
4164 if (result) {
4165 IPAERR("ipa interrupts initialization failed\n");
4166 return -ENODEV;
4167 }
4168
4169 /*add handler for suspend interrupt*/
4170 result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
4171 ipa3_suspend_handler, false, NULL);
4172 if (result) {
4173 IPAERR("register handler for suspend interrupt failed\n");
4174 result = -ENODEV;
4175 goto fail_add_interrupt_handler;
4176 }
4177
4178 return 0;
4179
4180fail_add_interrupt_handler:
4181 free_irq(ipa3_res.ipa_irq, master_dev);
4182 return result;
4183}
4184
4185/**
4186 * ipa3_destroy_flt_tbl_idrs() - destroy the idr structure for flt tables
4187 * The idr strcuture per filtering table is intended for rule id generation
4188 * per filtering rule.
4189 */
4190static void ipa3_destroy_flt_tbl_idrs(void)
4191{
4192 int i;
4193 struct ipa3_flt_tbl *flt_tbl;
4194
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004195 idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
4196 idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
4197
Amir Levy9659e592016-10-27 18:08:27 +03004198 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4199 if (!ipa_is_ep_support_flt(i))
4200 continue;
4201
4202 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004203 flt_tbl->rule_ids = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004204 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004205 flt_tbl->rule_ids = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004206 }
4207}
4208
4209static void ipa3_freeze_clock_vote_and_notify_modem(void)
4210{
4211 int res;
Amir Levy9659e592016-10-27 18:08:27 +03004212 struct ipa_active_client_logging_info log_info;
4213
4214 if (ipa3_ctx->smp2p_info.res_sent)
4215 return;
4216
Skylar Change1209942017-02-02 14:26:38 -08004217 if (ipa3_ctx->smp2p_info.out_base_id == 0) {
4218 IPAERR("smp2p out gpio not assigned\n");
4219 return;
4220 }
4221
Amir Levy9659e592016-10-27 18:08:27 +03004222 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "FREEZE_VOTE");
4223 res = ipa3_inc_client_enable_clks_no_block(&log_info);
4224 if (res)
Skylar Change1209942017-02-02 14:26:38 -08004225 ipa3_ctx->smp2p_info.ipa_clk_on = false;
Amir Levy9659e592016-10-27 18:08:27 +03004226 else
Skylar Change1209942017-02-02 14:26:38 -08004227 ipa3_ctx->smp2p_info.ipa_clk_on = true;
Amir Levy9659e592016-10-27 18:08:27 +03004228
Skylar Change1209942017-02-02 14:26:38 -08004229 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4230 IPA_GPIO_OUT_CLK_VOTE_IDX,
4231 ipa3_ctx->smp2p_info.ipa_clk_on);
4232 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4233 IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 1);
Amir Levy9659e592016-10-27 18:08:27 +03004234
Skylar Change1209942017-02-02 14:26:38 -08004235 ipa3_ctx->smp2p_info.res_sent = true;
4236 IPADBG("IPA clocks are %s\n",
4237 ipa3_ctx->smp2p_info.ipa_clk_on ? "ON" : "OFF");
4238}
4239
4240void ipa3_reset_freeze_vote(void)
4241{
4242 if (ipa3_ctx->smp2p_info.res_sent == false)
4243 return;
4244
4245 if (ipa3_ctx->smp2p_info.ipa_clk_on)
4246 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("FREEZE_VOTE");
4247
4248 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4249 IPA_GPIO_OUT_CLK_VOTE_IDX, 0);
4250 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4251 IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 0);
4252
4253 ipa3_ctx->smp2p_info.res_sent = false;
4254 ipa3_ctx->smp2p_info.ipa_clk_on = false;
Amir Levy9659e592016-10-27 18:08:27 +03004255}
4256
4257static int ipa3_panic_notifier(struct notifier_block *this,
4258 unsigned long event, void *ptr)
4259{
4260 int res;
4261
4262 ipa3_freeze_clock_vote_and_notify_modem();
4263
4264 IPADBG("Calling uC panic handler\n");
4265 res = ipa3_uc_panic_notifier(this, event, ptr);
4266 if (res)
4267 IPAERR("uC panic handler failed %d\n", res);
4268
4269 return NOTIFY_DONE;
4270}
4271
4272static struct notifier_block ipa3_panic_blk = {
4273 .notifier_call = ipa3_panic_notifier,
4274 /* IPA panic handler needs to run before modem shuts down */
4275 .priority = INT_MAX,
4276};
4277
4278static void ipa3_register_panic_hdlr(void)
4279{
4280 atomic_notifier_chain_register(&panic_notifier_list,
4281 &ipa3_panic_blk);
4282}
4283
4284static void ipa3_trigger_ipa_ready_cbs(void)
4285{
4286 struct ipa3_ready_cb_info *info;
4287
4288 mutex_lock(&ipa3_ctx->lock);
4289
4290 /* Call all the CBs */
4291 list_for_each_entry(info, &ipa3_ctx->ipa_ready_cb_list, link)
4292 if (info->ready_cb)
4293 info->ready_cb(info->user_data);
4294
4295 mutex_unlock(&ipa3_ctx->lock);
4296}
4297
4298static int ipa3_gsi_pre_fw_load_init(void)
4299{
4300 int result;
4301
4302 result = gsi_configure_regs(ipa3_res.transport_mem_base,
4303 ipa3_res.transport_mem_size,
4304 ipa3_res.ipa_mem_base);
4305 if (result) {
4306 IPAERR("Failed to configure GSI registers\n");
4307 return -EINVAL;
4308 }
4309
4310 return 0;
4311}
4312
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004313static void ipa3_uc_is_loaded(void)
4314{
4315 IPADBG("\n");
4316 complete_all(&ipa3_ctx->uc_loaded_completion_obj);
4317}
4318
Amir Levy41644242016-11-03 15:38:09 +02004319static enum gsi_ver ipa3_get_gsi_ver(enum ipa_hw_type ipa_hw_type)
4320{
4321 enum gsi_ver gsi_ver;
4322
4323 switch (ipa_hw_type) {
4324 case IPA_HW_v3_0:
4325 case IPA_HW_v3_1:
4326 gsi_ver = GSI_VER_1_0;
4327 break;
4328 case IPA_HW_v3_5:
4329 gsi_ver = GSI_VER_1_2;
4330 break;
4331 case IPA_HW_v3_5_1:
4332 gsi_ver = GSI_VER_1_3;
4333 break;
Michael Adisumarta891a4ff2017-05-16 16:40:06 -07004334 case IPA_HW_v4_0:
4335 gsi_ver = GSI_VER_2_0;
4336 break;
Amir Levy41644242016-11-03 15:38:09 +02004337 default:
4338 IPAERR("No GSI version for ipa type %d\n", ipa_hw_type);
4339 WARN_ON(1);
4340 gsi_ver = GSI_VER_ERR;
4341 }
4342
4343 IPADBG("GSI version %d\n", gsi_ver);
4344
4345 return gsi_ver;
4346}
4347
Amir Levy9659e592016-10-27 18:08:27 +03004348/**
4349 * ipa3_post_init() - Initialize the IPA Driver (Part II).
4350 * This part contains all initialization which requires interaction with
Amir Levya59ed3f2017-03-05 17:30:55 +02004351 * IPA HW (via GSI).
Amir Levy9659e592016-10-27 18:08:27 +03004352 *
4353 * @resource_p: contain platform specific values from DST file
4354 * @pdev: The platform device structure representing the IPA driver
4355 *
4356 * Function initialization process:
Amir Levy54fe4d32017-03-16 11:21:49 +02004357 * - Initialize endpoints bitmaps
4358 * - Initialize resource groups min and max values
4359 * - Initialize filtering lists heads and idr
4360 * - Initialize interrupts
Amir Levya59ed3f2017-03-05 17:30:55 +02004361 * - Register GSI
Amir Levy9659e592016-10-27 18:08:27 +03004362 * - Setup APPS pipes
4363 * - Initialize tethering bridge
4364 * - Initialize IPA debugfs
4365 * - Initialize IPA uC interface
4366 * - Initialize WDI interface
4367 * - Initialize USB interface
4368 * - Register for panic handler
4369 * - Trigger IPA ready callbacks (to all subscribers)
4370 * - Trigger IPA completion object (to all who wait on it)
4371 */
4372static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p,
4373 struct device *ipa_dev)
4374{
4375 int result;
Amir Levy9659e592016-10-27 18:08:27 +03004376 struct gsi_per_props gsi_props;
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004377 struct ipa3_uc_hdlrs uc_hdlrs = { 0 };
Amir Levy54fe4d32017-03-16 11:21:49 +02004378 struct ipa3_flt_tbl *flt_tbl;
4379 int i;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004380 struct idr *idr;
Amir Levy54fe4d32017-03-16 11:21:49 +02004381
Utkarsh Saxenaded78142017-05-03 14:04:30 +05304382 if (ipa3_ctx == NULL) {
4383 IPADBG("IPA driver haven't initialized\n");
4384 return -ENXIO;
4385 }
4386
4387 /* Prevent consequent calls from trying to load the FW again. */
4388 if (ipa3_ctx->ipa_initialization_complete)
4389 return 0;
4390
Amir Levy54fe4d32017-03-16 11:21:49 +02004391 /*
4392 * indication whether working in MHI config or non MHI config is given
4393 * in ipa3_write which is launched before ipa3_post_init. i.e. from
4394 * this point it is safe to use ipa3_ep_mapping array and the correct
4395 * entry will be returned from ipa3_get_hw_type_index()
4396 */
4397 ipa_init_ep_flt_bitmap();
4398 IPADBG("EP with flt support bitmap 0x%x (%u pipes)\n",
4399 ipa3_ctx->ep_flt_bitmap, ipa3_ctx->ep_flt_num);
4400
4401 /* Assign resource limitation to each group */
4402 ipa3_set_resorce_groups_min_max_limits();
4403
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004404 idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
4405 idr_init(idr);
4406 idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
4407 idr_init(idr);
4408
Amir Levy54fe4d32017-03-16 11:21:49 +02004409 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4410 if (!ipa_is_ep_support_flt(i))
4411 continue;
4412
4413 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
4414 INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
4415 flt_tbl->in_sys[IPA_RULE_HASHABLE] =
4416 !ipa3_ctx->ip4_flt_tbl_hash_lcl;
4417 flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
4418 !ipa3_ctx->ip4_flt_tbl_nhash_lcl;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004419 flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v4];
Amir Levy54fe4d32017-03-16 11:21:49 +02004420
4421 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
4422 INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
4423 flt_tbl->in_sys[IPA_RULE_HASHABLE] =
4424 !ipa3_ctx->ip6_flt_tbl_hash_lcl;
4425 flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
4426 !ipa3_ctx->ip6_flt_tbl_nhash_lcl;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004427 flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v6];
Amir Levy54fe4d32017-03-16 11:21:49 +02004428 }
4429
4430 if (!ipa3_ctx->apply_rg10_wa) {
4431 result = ipa3_init_interrupts();
4432 if (result) {
4433 IPAERR("ipa initialization of interrupts failed\n");
4434 result = -ENODEV;
4435 goto fail_register_device;
4436 }
4437 } else {
4438 IPADBG("Initialization of ipa interrupts skipped\n");
4439 }
Amir Levy9659e592016-10-27 18:08:27 +03004440
Amir Levy3afd94a2017-01-05 10:19:13 +02004441 /*
Amir Levy5cfbb322017-01-09 14:53:02 +02004442 * IPAv3.5 and above requires to disable prefetch for USB in order
4443 * to allow MBIM to work, currently MBIM is not needed in MHI mode.
Amir Levy3afd94a2017-01-05 10:19:13 +02004444 */
Michael Adisumartad68ab112017-06-14 11:40:06 -07004445 if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5
4446 && ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) &&
Amir Levy5cfbb322017-01-09 14:53:02 +02004447 (!ipa3_ctx->ipa_config_is_mhi))
Amir Levy3afd94a2017-01-05 10:19:13 +02004448 ipa3_disable_prefetch(IPA_CLIENT_USB_CONS);
4449
Amir Levya59ed3f2017-03-05 17:30:55 +02004450 memset(&gsi_props, 0, sizeof(gsi_props));
4451 gsi_props.ver = ipa3_get_gsi_ver(resource_p->ipa_hw_type);
4452 gsi_props.ee = resource_p->ee;
4453 gsi_props.intr = GSI_INTR_IRQ;
4454 gsi_props.irq = resource_p->transport_irq;
4455 gsi_props.phys_addr = resource_p->transport_mem_base;
4456 gsi_props.size = resource_p->transport_mem_size;
4457 gsi_props.notify_cb = ipa_gsi_notify_cb;
4458 gsi_props.req_clk_cb = NULL;
4459 gsi_props.rel_clk_cb = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004460
Ghanim Fodic823bc62017-10-21 17:29:53 +03004461 if (ipa3_ctx->ipa_config_is_mhi) {
4462 gsi_props.mhi_er_id_limits_valid = true;
4463 gsi_props.mhi_er_id_limits[0] = resource_p->mhi_evid_limits[0];
4464 gsi_props.mhi_er_id_limits[1] = resource_p->mhi_evid_limits[1];
4465 }
4466
Amir Levya59ed3f2017-03-05 17:30:55 +02004467 result = gsi_register_device(&gsi_props,
4468 &ipa3_ctx->gsi_dev_hdl);
4469 if (result != GSI_STATUS_SUCCESS) {
4470 IPAERR(":gsi register error - %d\n", result);
4471 result = -ENODEV;
4472 goto fail_register_device;
Amir Levy9659e592016-10-27 18:08:27 +03004473 }
Amir Levya59ed3f2017-03-05 17:30:55 +02004474 IPADBG("IPA gsi is registered\n");
Amir Levy9659e592016-10-27 18:08:27 +03004475
4476 /* setup the AP-IPA pipes */
4477 if (ipa3_setup_apps_pipes()) {
4478 IPAERR(":failed to setup IPA-Apps pipes\n");
4479 result = -ENODEV;
4480 goto fail_setup_apps_pipes;
4481 }
Amir Levya59ed3f2017-03-05 17:30:55 +02004482 IPADBG("IPA GPI pipes were connected\n");
Amir Levy9659e592016-10-27 18:08:27 +03004483
4484 if (ipa3_ctx->use_ipa_teth_bridge) {
4485 /* Initialize the tethering bridge driver */
4486 result = ipa3_teth_bridge_driver_init();
4487 if (result) {
4488 IPAERR(":teth_bridge init failed (%d)\n", -result);
4489 result = -ENODEV;
4490 goto fail_teth_bridge_driver_init;
4491 }
4492 IPADBG("teth_bridge initialized");
4493 }
4494
4495 ipa3_debugfs_init();
4496
4497 result = ipa3_uc_interface_init();
4498 if (result)
4499 IPAERR(":ipa Uc interface init failed (%d)\n", -result);
4500 else
4501 IPADBG(":ipa Uc interface init ok\n");
4502
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004503 uc_hdlrs.ipa_uc_loaded_hdlr = ipa3_uc_is_loaded;
4504 ipa3_uc_register_handlers(IPA_HW_FEATURE_COMMON, &uc_hdlrs);
4505
Amir Levy9659e592016-10-27 18:08:27 +03004506 result = ipa3_wdi_init();
4507 if (result)
4508 IPAERR(":wdi init failed (%d)\n", -result);
4509 else
4510 IPADBG(":wdi init ok\n");
4511
4512 result = ipa3_ntn_init();
4513 if (result)
4514 IPAERR(":ntn init failed (%d)\n", -result);
4515 else
4516 IPADBG(":ntn init ok\n");
4517
Skylar Chang6f6e3072017-07-28 10:03:47 -07004518 result = ipa_hw_stats_init();
4519 if (result)
4520 IPAERR("fail to init stats %d\n", result);
4521 else
4522 IPADBG(":stats init ok\n");
4523
Amir Levy9659e592016-10-27 18:08:27 +03004524 ipa3_register_panic_hdlr();
4525
4526 ipa3_ctx->q6_proxy_clk_vote_valid = true;
Mohammed Javid05b05d02017-11-13 23:43:27 +05304527 ipa3_ctx->q6_proxy_clk_vote_cnt++;
Amir Levy9659e592016-10-27 18:08:27 +03004528
4529 mutex_lock(&ipa3_ctx->lock);
4530 ipa3_ctx->ipa_initialization_complete = true;
4531 mutex_unlock(&ipa3_ctx->lock);
4532
4533 ipa3_trigger_ipa_ready_cbs();
4534 complete_all(&ipa3_ctx->init_completion_obj);
4535 pr_info("IPA driver initialization was successful.\n");
4536
4537 return 0;
4538
4539fail_teth_bridge_driver_init:
4540 ipa3_teardown_apps_pipes();
4541fail_setup_apps_pipes:
Amir Levya59ed3f2017-03-05 17:30:55 +02004542 gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03004543fail_register_device:
Amir Levy9659e592016-10-27 18:08:27 +03004544 ipa3_destroy_flt_tbl_idrs();
Amir Levy9659e592016-10-27 18:08:27 +03004545 return result;
4546}
4547
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004548static int ipa3_manual_load_ipa_fws(void)
Amir Levy9659e592016-10-27 18:08:27 +03004549{
4550 int result;
4551 const struct firmware *fw;
4552
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004553 IPADBG("Manual FW loading process initiated\n");
Amir Levy9659e592016-10-27 18:08:27 +03004554
4555 result = request_firmware(&fw, IPA_FWS_PATH, ipa3_ctx->dev);
4556 if (result < 0) {
4557 IPAERR("request_firmware failed, error %d\n", result);
4558 return result;
4559 }
4560 if (fw == NULL) {
4561 IPAERR("Firmware is NULL!\n");
4562 return -EINVAL;
4563 }
4564
4565 IPADBG("FWs are available for loading\n");
4566
Ghanim Fodi37b64952017-01-24 15:42:30 +02004567 result = ipa3_load_fws(fw, ipa3_res.transport_mem_base);
Amir Levy9659e592016-10-27 18:08:27 +03004568 if (result) {
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004569 IPAERR("Manual IPA FWs loading has failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03004570 release_firmware(fw);
4571 return result;
4572 }
4573
4574 result = gsi_enable_fw(ipa3_res.transport_mem_base,
Amir Levy85dcd172016-12-06 17:47:39 +02004575 ipa3_res.transport_mem_size,
4576 ipa3_get_gsi_ver(ipa3_res.ipa_hw_type));
Amir Levy9659e592016-10-27 18:08:27 +03004577 if (result) {
4578 IPAERR("Failed to enable GSI FW\n");
4579 release_firmware(fw);
4580 return result;
4581 }
4582
4583 release_firmware(fw);
4584
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004585 IPADBG("Manual FW loading process is complete\n");
Amir Levy9659e592016-10-27 18:08:27 +03004586 return 0;
4587}
4588
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004589static int ipa3_pil_load_ipa_fws(void)
Amir Levy9659e592016-10-27 18:08:27 +03004590{
4591 void *subsystem_get_retval = NULL;
4592
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004593 IPADBG("PIL FW loading process initiated\n");
Amir Levy9659e592016-10-27 18:08:27 +03004594
4595 subsystem_get_retval = subsystem_get(IPA_SUBSYSTEM_NAME);
4596 if (IS_ERR_OR_NULL(subsystem_get_retval)) {
4597 IPAERR("Unable to trigger PIL process for FW loading\n");
4598 return -EINVAL;
4599 }
4600
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004601 IPADBG("PIL FW loading process is complete\n");
Amir Levy9659e592016-10-27 18:08:27 +03004602 return 0;
4603}
4604
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004605static void ipa3_load_ipa_fw(struct work_struct *work)
4606{
4607 int result;
4608
4609 IPADBG("Entry\n");
4610
4611 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
4612
4613 if (ipa3_is_msm_device() || (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5))
4614 result = ipa3_pil_load_ipa_fws();
4615 else
4616 result = ipa3_manual_load_ipa_fws();
4617
4618 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
4619
4620 if (result) {
4621 IPAERR("IPA FW loading process has failed\n");
4622 return;
4623 }
4624 pr_info("IPA FW loaded successfully\n");
4625
4626 result = ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
4627 if (result)
4628 IPAERR("IPA post init failed %d\n", result);
4629}
4630
Amir Levy9659e592016-10-27 18:08:27 +03004631static ssize_t ipa3_write(struct file *file, const char __user *buf,
4632 size_t count, loff_t *ppos)
4633{
4634 unsigned long missing;
Amir Levy9659e592016-10-27 18:08:27 +03004635
Amir Levy2da9d452017-12-12 10:09:46 +02004636 char dbg_buff[32] = { 0 };
Amir Levy9659e592016-10-27 18:08:27 +03004637
4638 if (sizeof(dbg_buff) < count + 1)
4639 return -EFAULT;
4640
4641 missing = copy_from_user(dbg_buff, buf, count);
4642
4643 if (missing) {
4644 IPAERR("Unable to copy data from user\n");
4645 return -EFAULT;
4646 }
4647
Mohammed Javidbf4c8022017-08-07 23:15:48 +05304648 if (count > 0)
4649 dbg_buff[count - 1] = '\0';
4650
Amir Levy2da9d452017-12-12 10:09:46 +02004651 IPADBG("user input string %s\n", dbg_buff);
4652
Amir Levy9659e592016-10-27 18:08:27 +03004653 /* Prevent consequent calls from trying to load the FW again. */
4654 if (ipa3_is_ready())
4655 return count;
4656
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004657 /* Check MHI configuration on MDM devices */
4658 if (!ipa3_is_msm_device()) {
Amir Levy2da9d452017-12-12 10:09:46 +02004659
4660 if (strnstr(dbg_buff, "vlan", strlen(dbg_buff))) {
4661 if (strnstr(dbg_buff, "eth", strlen(dbg_buff)))
4662 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_EMAC] =
4663 true;
4664 if (strnstr(dbg_buff, "rndis", strlen(dbg_buff)))
4665 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_RNDIS] =
4666 true;
4667 if (strnstr(dbg_buff, "ecm", strlen(dbg_buff)))
4668 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM] =
4669 true;
4670
4671 /*
4672 * when vlan mode is passed to our dev we expect
4673 * another write
4674 */
4675 return count;
4676 }
4677
Amir Levy54fe4d32017-03-16 11:21:49 +02004678 if (!strcasecmp(dbg_buff, "MHI")) {
4679 ipa3_ctx->ipa_config_is_mhi = true;
4680 pr_info(
Amir Levy2da9d452017-12-12 10:09:46 +02004681 "IPA is loading with MHI configuration\n");
4682 } else if (!strcmp(dbg_buff, "1\n")) {
Amir Levy54fe4d32017-03-16 11:21:49 +02004683 pr_info(
Amir Levy2da9d452017-12-12 10:09:46 +02004684 "IPA is loading with non MHI configuration\n");
4685 } else {
4686 IPAERR("got invalid string %s not loading FW\n",
4687 dbg_buff);
4688 return count;
Amir Levy54fe4d32017-03-16 11:21:49 +02004689 }
Amir Levy54fe4d32017-03-16 11:21:49 +02004690 }
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004691
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004692 queue_work(ipa3_ctx->transport_power_mgmt_wq,
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004693 &ipa3_fw_loading_work);
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004694
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004695 IPADBG("Scheduled a work to load IPA FW\n");
Amir Levy9659e592016-10-27 18:08:27 +03004696 return count;
4697}
4698
Skylar Chang48afa052017-10-25 09:32:57 -07004699/**
4700 * ipa3_tz_unlock_reg - Unlocks memory regions so that they become accessible
4701 * from AP.
4702 * @reg_info - Pointer to array of memory regions to unlock
4703 * @num_regs - Number of elements in the array
4704 *
4705 * Converts the input array of regions to a struct that TZ understands and
4706 * issues an SCM call.
4707 * Also flushes the memory cache to DDR in order to make sure that TZ sees the
4708 * correct data structure.
4709 *
4710 * Returns: 0 on success, negative on failure
4711 */
4712int ipa3_tz_unlock_reg(struct ipa_tz_unlock_reg_info *reg_info, u16 num_regs)
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004713{
4714 int i, size, ret, resp;
4715 struct tz_smmu_ipa_protect_region_iovec_s *ipa_tz_unlock_vec;
4716 struct tz_smmu_ipa_protect_region_s cmd_buf;
Skylar Chang3a696ba2017-10-25 09:35:07 -07004717 struct scm_desc desc = {0};
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004718
Skylar Chang48afa052017-10-25 09:32:57 -07004719 if (reg_info == NULL || num_regs == 0) {
4720 IPAERR("Bad parameters\n");
4721 return -EFAULT;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004722 }
Skylar Chang48afa052017-10-25 09:32:57 -07004723
4724 size = num_regs * sizeof(struct tz_smmu_ipa_protect_region_iovec_s);
4725 ipa_tz_unlock_vec = kzalloc(PAGE_ALIGN(size), GFP_KERNEL);
4726 if (ipa_tz_unlock_vec == NULL)
4727 return -ENOMEM;
4728
4729 for (i = 0; i < num_regs; i++) {
4730 ipa_tz_unlock_vec[i].input_addr = reg_info[i].reg_addr ^
4731 (reg_info[i].reg_addr & 0xFFF);
4732 ipa_tz_unlock_vec[i].output_addr = reg_info[i].reg_addr ^
4733 (reg_info[i].reg_addr & 0xFFF);
4734 ipa_tz_unlock_vec[i].size = reg_info[i].size;
4735 ipa_tz_unlock_vec[i].attr = IPA_TZ_UNLOCK_ATTRIBUTE;
4736 }
4737
4738 /* pass physical address of command buffer */
4739 cmd_buf.iovec_buf = virt_to_phys((void *)ipa_tz_unlock_vec);
4740 cmd_buf.size_bytes = size;
4741
4742 /* flush cache to DDR */
4743 __cpuc_flush_dcache_area((void *)ipa_tz_unlock_vec, size);
4744 outer_flush_range(cmd_buf.iovec_buf, cmd_buf.iovec_buf + size);
Skylar Chang3a696ba2017-10-25 09:35:07 -07004745 if (!is_scm_armv8())
4746 ret = scm_call(SCM_SVC_MP, TZ_MEM_PROTECT_REGION_ID,
4747 &cmd_buf, sizeof(cmd_buf), &resp, sizeof(resp));
4748 else {
4749 desc.args[0] = virt_to_phys((void *)ipa_tz_unlock_vec);
4750 desc.args[1] = size;
4751 desc.arginfo = SCM_ARGS(2, SCM_RO, SCM_VAL);
4752 ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
4753 TZ_MEM_PROTECT_REGION_ID), &desc);
4754 }
Skylar Chang48afa052017-10-25 09:32:57 -07004755
Skylar Chang48afa052017-10-25 09:32:57 -07004756 if (ret) {
4757 IPAERR("scm call SCM_SVC_MP failed: %d\n", ret);
4758 kfree(ipa_tz_unlock_vec);
4759 return -EFAULT;
4760 }
4761 kfree(ipa_tz_unlock_vec);
4762
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004763 return 0;
4764}
4765
Skylar Changcd3902d2017-03-27 18:08:27 -07004766static int ipa3_alloc_pkt_init(void)
4767{
4768 struct ipa_mem_buffer mem;
4769 struct ipahal_imm_cmd_pyld *cmd_pyld;
4770 struct ipahal_imm_cmd_ip_packet_init cmd = {0};
4771 int i;
4772
4773 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
4774 &cmd, false);
4775 if (!cmd_pyld) {
4776 IPAERR("failed to construct IMM cmd\n");
4777 return -ENOMEM;
4778 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -07004779 ipa3_ctx->pkt_init_imm_opcode = cmd_pyld->opcode;
Skylar Changcd3902d2017-03-27 18:08:27 -07004780
4781 mem.size = cmd_pyld->len * ipa3_ctx->ipa_num_pipes;
4782 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
4783 &mem.phys_base, GFP_KERNEL);
4784 if (!mem.base) {
4785 IPAERR("failed to alloc DMA buff of size %d\n", mem.size);
4786 ipahal_destroy_imm_cmd(cmd_pyld);
4787 return -ENOMEM;
4788 }
4789 ipahal_destroy_imm_cmd(cmd_pyld);
4790
4791 memset(mem.base, 0, mem.size);
4792 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4793 cmd.destination_pipe_index = i;
4794 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
4795 &cmd, false);
4796 if (!cmd_pyld) {
4797 IPAERR("failed to construct IMM cmd\n");
4798 dma_free_coherent(ipa3_ctx->pdev,
4799 mem.size,
4800 mem.base,
4801 mem.phys_base);
4802 return -ENOMEM;
4803 }
4804 memcpy(mem.base + i * cmd_pyld->len, cmd_pyld->data,
4805 cmd_pyld->len);
4806 ipa3_ctx->pkt_init_imm[i] = mem.phys_base + i * cmd_pyld->len;
4807 ipahal_destroy_imm_cmd(cmd_pyld);
4808 }
4809
4810 return 0;
4811}
4812
Amir Levy9659e592016-10-27 18:08:27 +03004813/**
4814* ipa3_pre_init() - Initialize the IPA Driver.
4815* This part contains all initialization which doesn't require IPA HW, such
4816* as structure allocations and initializations, register writes, etc.
4817*
4818* @resource_p: contain platform specific values from DST file
4819* @pdev: The platform device structure representing the IPA driver
4820*
4821* Function initialization process:
Amir Levy54fe4d32017-03-16 11:21:49 +02004822* Allocate memory for the driver context data struct
4823* Initializing the ipa3_ctx with :
Amir Levy9659e592016-10-27 18:08:27 +03004824* 1)parsed values from the dts file
4825* 2)parameters passed to the module initialization
4826* 3)read HW values(such as core memory size)
Amir Levy54fe4d32017-03-16 11:21:49 +02004827* Map IPA core registers to CPU memory
4828* Restart IPA core(HW reset)
4829* Initialize the look-aside caches(kmem_cache/slab) for filter,
Amir Levy9659e592016-10-27 18:08:27 +03004830* routing and IPA-tree
Amir Levy54fe4d32017-03-16 11:21:49 +02004831* Create memory pool with 4 objects for DMA operations(each object
Amir Levy9659e592016-10-27 18:08:27 +03004832* is 512Bytes long), this object will be use for tx(A5->IPA)
Amir Levy54fe4d32017-03-16 11:21:49 +02004833* Initialize lists head(routing, hdr, system pipes)
4834* Initialize mutexes (for ipa_ctx and NAT memory mutexes)
4835* Initialize spinlocks (for list related to A5<->IPA pipes)
4836* Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq"
4837* Initialize Red-Black-Tree(s) for handles of header,routing rule,
4838* routing table ,filtering rule
4839* Initialize the filter block by committing IPV4 and IPV6 default rules
4840* Create empty routing table in system memory(no committing)
4841* Create a char-device for IPA
4842* Initialize IPA RM (resource manager)
4843* Configure GSI registers (in GSI case)
Amir Levy9659e592016-10-27 18:08:27 +03004844*/
4845static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
4846 struct device *ipa_dev)
4847{
4848 int result = 0;
4849 int i;
Amir Levy9659e592016-10-27 18:08:27 +03004850 struct ipa3_rt_tbl_set *rset;
4851 struct ipa_active_client_logging_info log_info;
4852
4853 IPADBG("IPA Driver initialization started\n");
4854
4855 ipa3_ctx = kzalloc(sizeof(*ipa3_ctx), GFP_KERNEL);
4856 if (!ipa3_ctx) {
4857 IPAERR(":kzalloc err.\n");
4858 result = -ENOMEM;
4859 goto fail_mem_ctx;
4860 }
4861
4862 ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0);
Skylar Chang841c1452017-04-03 16:07:22 -07004863 if (ipa3_ctx->logbuf == NULL)
4864 IPAERR("failed to create IPC log, continue...\n");
Amir Levy9659e592016-10-27 18:08:27 +03004865
4866 ipa3_ctx->pdev = ipa_dev;
4867 ipa3_ctx->uc_pdev = ipa_dev;
4868 ipa3_ctx->smmu_present = smmu_info.present;
Michael Adisumarta93e97522017-10-06 15:49:46 -07004869 if (!ipa3_ctx->smmu_present) {
4870 for (i = 0; i < IPA_SMMU_CB_MAX; i++)
4871 ipa3_ctx->s1_bypass_arr[i] = true;
4872 } else {
Michael Adisumarta972e33e2017-10-20 15:24:27 -07004873 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] =
4874 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP];
Michael Adisumarta93e97522017-10-06 15:49:46 -07004875 }
4876
Amir Levy9659e592016-10-27 18:08:27 +03004877 ipa3_ctx->ipa_wrapper_base = resource_p->ipa_mem_base;
4878 ipa3_ctx->ipa_wrapper_size = resource_p->ipa_mem_size;
4879 ipa3_ctx->ipa_hw_type = resource_p->ipa_hw_type;
4880 ipa3_ctx->ipa3_hw_mode = resource_p->ipa3_hw_mode;
4881 ipa3_ctx->use_ipa_teth_bridge = resource_p->use_ipa_teth_bridge;
Amir Levy9659e592016-10-27 18:08:27 +03004882 ipa3_ctx->modem_cfg_emb_pipe_flt = resource_p->modem_cfg_emb_pipe_flt;
4883 ipa3_ctx->ipa_wdi2 = resource_p->ipa_wdi2;
4884 ipa3_ctx->use_64_bit_dma_mask = resource_p->use_64_bit_dma_mask;
4885 ipa3_ctx->wan_rx_ring_size = resource_p->wan_rx_ring_size;
4886 ipa3_ctx->lan_rx_ring_size = resource_p->lan_rx_ring_size;
4887 ipa3_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
4888 ipa3_ctx->tethered_flow_control = resource_p->tethered_flow_control;
Amir Levy9659e592016-10-27 18:08:27 +03004889 ipa3_ctx->ee = resource_p->ee;
4890 ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa;
4891 ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa;
Michael Adisumarta3e350812017-09-18 14:54:36 -07004892 ipa3_ctx->use_ipa_pm = resource_p->use_ipa_pm;
Amir Levy9659e592016-10-27 18:08:27 +03004893 ipa3_ctx->ipa3_active_clients_logging.log_rdy = false;
Ghanim Fodic823bc62017-10-21 17:29:53 +03004894 ipa3_ctx->mhi_evid_limits[0] = resource_p->mhi_evid_limits[0];
4895 ipa3_ctx->mhi_evid_limits[1] = resource_p->mhi_evid_limits[1];
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004896 if (resource_p->ipa_tz_unlock_reg) {
4897 ipa3_ctx->ipa_tz_unlock_reg_num =
4898 resource_p->ipa_tz_unlock_reg_num;
4899 ipa3_ctx->ipa_tz_unlock_reg = kcalloc(
4900 ipa3_ctx->ipa_tz_unlock_reg_num,
4901 sizeof(*ipa3_ctx->ipa_tz_unlock_reg),
4902 GFP_KERNEL);
4903 if (ipa3_ctx->ipa_tz_unlock_reg == NULL) {
4904 result = -ENOMEM;
4905 goto fail_tz_unlock_reg;
4906 }
4907 for (i = 0; i < ipa3_ctx->ipa_tz_unlock_reg_num; i++) {
4908 ipa3_ctx->ipa_tz_unlock_reg[i].reg_addr =
4909 resource_p->ipa_tz_unlock_reg[i].reg_addr;
4910 ipa3_ctx->ipa_tz_unlock_reg[i].size =
4911 resource_p->ipa_tz_unlock_reg[i].size;
4912 }
4913 }
4914
4915 /* unlock registers for uc */
Skylar Chang48afa052017-10-25 09:32:57 -07004916 result = ipa3_tz_unlock_reg(ipa3_ctx->ipa_tz_unlock_reg,
4917 ipa3_ctx->ipa_tz_unlock_reg_num);
4918 if (result)
4919 IPAERR("Failed to unlock memory region using TZ\n");
Amir Levy9659e592016-10-27 18:08:27 +03004920
4921 /* default aggregation parameters */
4922 ipa3_ctx->aggregation_type = IPA_MBIM_16;
4923 ipa3_ctx->aggregation_byte_limit = 1;
4924 ipa3_ctx->aggregation_time_limit = 0;
4925
4926 ipa3_ctx->ctrl = kzalloc(sizeof(*ipa3_ctx->ctrl), GFP_KERNEL);
4927 if (!ipa3_ctx->ctrl) {
4928 IPAERR("memory allocation error for ctrl\n");
4929 result = -ENOMEM;
4930 goto fail_mem_ctrl;
4931 }
4932 result = ipa3_controller_static_bind(ipa3_ctx->ctrl,
4933 ipa3_ctx->ipa_hw_type);
4934 if (result) {
4935 IPAERR("fail to static bind IPA ctrl.\n");
4936 result = -EFAULT;
4937 goto fail_bind;
4938 }
4939
4940 result = ipa3_init_mem_partition(master_dev->of_node);
4941 if (result) {
4942 IPAERR(":ipa3_init_mem_partition failed!\n");
4943 result = -ENODEV;
4944 goto fail_init_mem_partition;
4945 }
4946
4947 if (ipa3_bus_scale_table) {
Ghanim Fodi6a831342017-03-07 18:19:15 +02004948 IPADBG("Use bus scaling info from device tree #usecases=%d\n",
4949 ipa3_bus_scale_table->num_usecases);
Amir Levy9659e592016-10-27 18:08:27 +03004950 ipa3_ctx->ctrl->msm_bus_data_ptr = ipa3_bus_scale_table;
4951 }
4952
Ghanim Fodi6a831342017-03-07 18:19:15 +02004953 /* get BUS handle */
4954 ipa3_ctx->ipa_bus_hdl =
4955 msm_bus_scale_register_client(
4956 ipa3_ctx->ctrl->msm_bus_data_ptr);
4957 if (!ipa3_ctx->ipa_bus_hdl) {
4958 IPAERR("fail to register with bus mgr!\n");
4959 result = -ENODEV;
4960 goto fail_bus_reg;
Amir Levy9659e592016-10-27 18:08:27 +03004961 }
4962
4963 /* get IPA clocks */
4964 result = ipa3_get_clks(master_dev);
4965 if (result)
4966 goto fail_clk;
4967
4968 /* init active_clients_log after getting ipa-clk */
4969 if (ipa3_active_clients_log_init())
4970 goto fail_init_active_client;
4971
4972 /* Enable ipa3_ctx->enable_clock_scaling */
4973 ipa3_ctx->enable_clock_scaling = 1;
4974 ipa3_ctx->curr_ipa_clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
4975
4976 /* enable IPA clocks explicitly to allow the initialization */
4977 ipa3_enable_clks();
4978
4979 /* setup IPA register access */
4980 IPADBG("Mapping 0x%x\n", resource_p->ipa_mem_base +
4981 ipa3_ctx->ctrl->ipa_reg_base_ofst);
4982 ipa3_ctx->mmio = ioremap(resource_p->ipa_mem_base +
4983 ipa3_ctx->ctrl->ipa_reg_base_ofst,
4984 resource_p->ipa_mem_size);
4985 if (!ipa3_ctx->mmio) {
4986 IPAERR(":ipa-base ioremap err.\n");
4987 result = -EFAULT;
4988 goto fail_remap;
4989 }
4990
4991 if (ipahal_init(ipa3_ctx->ipa_hw_type, ipa3_ctx->mmio,
4992 ipa3_ctx->pdev)) {
4993 IPAERR("fail to init ipahal\n");
4994 result = -EFAULT;
4995 goto fail_ipahal;
4996 }
4997
4998 result = ipa3_init_hw();
4999 if (result) {
5000 IPAERR(":error initializing HW.\n");
5001 result = -ENODEV;
5002 goto fail_init_hw;
5003 }
5004 IPADBG("IPA HW initialization sequence completed");
5005
5006 ipa3_ctx->ipa_num_pipes = ipa3_get_num_pipes();
5007 if (ipa3_ctx->ipa_num_pipes > IPA3_MAX_NUM_PIPES) {
5008 IPAERR("IPA has more pipes then supported! has %d, max %d\n",
5009 ipa3_ctx->ipa_num_pipes, IPA3_MAX_NUM_PIPES);
5010 result = -ENODEV;
5011 goto fail_init_hw;
5012 }
5013
Amir Levy9659e592016-10-27 18:08:27 +03005014 ipa3_ctx->ctrl->ipa_sram_read_settings();
5015 IPADBG("SRAM, size: 0x%x, restricted bytes: 0x%x\n",
5016 ipa3_ctx->smem_sz, ipa3_ctx->smem_restricted_bytes);
5017
5018 IPADBG("hdr_lcl=%u ip4_rt_hash=%u ip4_rt_nonhash=%u\n",
5019 ipa3_ctx->hdr_tbl_lcl, ipa3_ctx->ip4_rt_tbl_hash_lcl,
5020 ipa3_ctx->ip4_rt_tbl_nhash_lcl);
5021
5022 IPADBG("ip6_rt_hash=%u ip6_rt_nonhash=%u\n",
5023 ipa3_ctx->ip6_rt_tbl_hash_lcl, ipa3_ctx->ip6_rt_tbl_nhash_lcl);
5024
5025 IPADBG("ip4_flt_hash=%u ip4_flt_nonhash=%u\n",
5026 ipa3_ctx->ip4_flt_tbl_hash_lcl,
5027 ipa3_ctx->ip4_flt_tbl_nhash_lcl);
5028
5029 IPADBG("ip6_flt_hash=%u ip6_flt_nonhash=%u\n",
5030 ipa3_ctx->ip6_flt_tbl_hash_lcl,
5031 ipa3_ctx->ip6_flt_tbl_nhash_lcl);
5032
5033 if (ipa3_ctx->smem_reqd_sz > ipa3_ctx->smem_sz) {
5034 IPAERR("SW expect more core memory, needed %d, avail %d\n",
5035 ipa3_ctx->smem_reqd_sz, ipa3_ctx->smem_sz);
5036 result = -ENOMEM;
5037 goto fail_init_hw;
5038 }
5039
5040 mutex_init(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03005041 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE");
5042 ipa3_active_clients_log_inc(&log_info, false);
Skylar Chang242952b2017-07-20 15:04:05 -07005043 atomic_set(&ipa3_ctx->ipa3_active_clients.cnt, 1);
Amir Levy9659e592016-10-27 18:08:27 +03005044
Amir Levy9659e592016-10-27 18:08:27 +03005045 /* Create workqueues for power management */
5046 ipa3_ctx->power_mgmt_wq =
5047 create_singlethread_workqueue("ipa_power_mgmt");
5048 if (!ipa3_ctx->power_mgmt_wq) {
5049 IPAERR("failed to create power mgmt wq\n");
5050 result = -ENOMEM;
5051 goto fail_init_hw;
5052 }
5053
5054 ipa3_ctx->transport_power_mgmt_wq =
5055 create_singlethread_workqueue("transport_power_mgmt");
5056 if (!ipa3_ctx->transport_power_mgmt_wq) {
5057 IPAERR("failed to create transport power mgmt wq\n");
5058 result = -ENOMEM;
5059 goto fail_create_transport_wq;
5060 }
5061
Sridhar Ancha99b505b2016-04-21 23:11:10 +05305062 mutex_init(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03005063
5064 /* init the lookaside cache */
5065 ipa3_ctx->flt_rule_cache = kmem_cache_create("IPA_FLT",
5066 sizeof(struct ipa3_flt_entry), 0, 0, NULL);
5067 if (!ipa3_ctx->flt_rule_cache) {
5068 IPAERR(":ipa flt cache create failed\n");
5069 result = -ENOMEM;
5070 goto fail_flt_rule_cache;
5071 }
5072 ipa3_ctx->rt_rule_cache = kmem_cache_create("IPA_RT",
5073 sizeof(struct ipa3_rt_entry), 0, 0, NULL);
5074 if (!ipa3_ctx->rt_rule_cache) {
5075 IPAERR(":ipa rt cache create failed\n");
5076 result = -ENOMEM;
5077 goto fail_rt_rule_cache;
5078 }
5079 ipa3_ctx->hdr_cache = kmem_cache_create("IPA_HDR",
5080 sizeof(struct ipa3_hdr_entry), 0, 0, NULL);
5081 if (!ipa3_ctx->hdr_cache) {
5082 IPAERR(":ipa hdr cache create failed\n");
5083 result = -ENOMEM;
5084 goto fail_hdr_cache;
5085 }
5086 ipa3_ctx->hdr_offset_cache =
5087 kmem_cache_create("IPA_HDR_OFFSET",
5088 sizeof(struct ipa_hdr_offset_entry), 0, 0, NULL);
5089 if (!ipa3_ctx->hdr_offset_cache) {
5090 IPAERR(":ipa hdr off cache create failed\n");
5091 result = -ENOMEM;
5092 goto fail_hdr_offset_cache;
5093 }
5094 ipa3_ctx->hdr_proc_ctx_cache = kmem_cache_create("IPA_HDR_PROC_CTX",
5095 sizeof(struct ipa3_hdr_proc_ctx_entry), 0, 0, NULL);
5096 if (!ipa3_ctx->hdr_proc_ctx_cache) {
5097 IPAERR(":ipa hdr proc ctx cache create failed\n");
5098 result = -ENOMEM;
5099 goto fail_hdr_proc_ctx_cache;
5100 }
5101 ipa3_ctx->hdr_proc_ctx_offset_cache =
5102 kmem_cache_create("IPA_HDR_PROC_CTX_OFFSET",
5103 sizeof(struct ipa3_hdr_proc_ctx_offset_entry), 0, 0, NULL);
5104 if (!ipa3_ctx->hdr_proc_ctx_offset_cache) {
5105 IPAERR(":ipa hdr proc ctx off cache create failed\n");
5106 result = -ENOMEM;
5107 goto fail_hdr_proc_ctx_offset_cache;
5108 }
5109 ipa3_ctx->rt_tbl_cache = kmem_cache_create("IPA_RT_TBL",
5110 sizeof(struct ipa3_rt_tbl), 0, 0, NULL);
5111 if (!ipa3_ctx->rt_tbl_cache) {
5112 IPAERR(":ipa rt tbl cache create failed\n");
5113 result = -ENOMEM;
5114 goto fail_rt_tbl_cache;
5115 }
5116 ipa3_ctx->tx_pkt_wrapper_cache =
5117 kmem_cache_create("IPA_TX_PKT_WRAPPER",
5118 sizeof(struct ipa3_tx_pkt_wrapper), 0, 0, NULL);
5119 if (!ipa3_ctx->tx_pkt_wrapper_cache) {
5120 IPAERR(":ipa tx pkt wrapper cache create failed\n");
5121 result = -ENOMEM;
5122 goto fail_tx_pkt_wrapper_cache;
5123 }
5124 ipa3_ctx->rx_pkt_wrapper_cache =
5125 kmem_cache_create("IPA_RX_PKT_WRAPPER",
5126 sizeof(struct ipa3_rx_pkt_wrapper), 0, 0, NULL);
5127 if (!ipa3_ctx->rx_pkt_wrapper_cache) {
5128 IPAERR(":ipa rx pkt wrapper cache create failed\n");
5129 result = -ENOMEM;
5130 goto fail_rx_pkt_wrapper_cache;
5131 }
5132
Skylar Chang6c4bec92017-04-21 16:10:14 -07005133 /* allocate memory for DMA_TASK workaround */
5134 result = ipa3_allocate_dma_task_for_gsi();
5135 if (result) {
5136 IPAERR("failed to allocate dma task\n");
5137 goto fail_dma_task;
5138 }
5139
Amir Levy9659e592016-10-27 18:08:27 +03005140 /* init the various list heads */
5141 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_hdr_entry_list);
5142 for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
5143 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_offset_list[i]);
5144 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_free_offset_list[i]);
5145 }
5146 INIT_LIST_HEAD(&ipa3_ctx->hdr_proc_ctx_tbl.head_proc_ctx_entry_list);
5147 for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) {
5148 INIT_LIST_HEAD(&ipa3_ctx->hdr_proc_ctx_tbl.head_offset_list[i]);
5149 INIT_LIST_HEAD(&ipa3_ctx->
5150 hdr_proc_ctx_tbl.head_free_offset_list[i]);
5151 }
5152 INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005153 idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005154 INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005155 idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005156
5157 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
5158 INIT_LIST_HEAD(&rset->head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005159 idr_init(&rset->rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005160 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
5161 INIT_LIST_HEAD(&rset->head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005162 idr_init(&rset->rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005163
5164 INIT_LIST_HEAD(&ipa3_ctx->intf_list);
5165 INIT_LIST_HEAD(&ipa3_ctx->msg_list);
5166 INIT_LIST_HEAD(&ipa3_ctx->pull_msg_list);
5167 init_waitqueue_head(&ipa3_ctx->msg_waitq);
5168 mutex_init(&ipa3_ctx->msg_lock);
5169
5170 mutex_init(&ipa3_ctx->lock);
Skylar Changfb792c62017-08-17 12:53:23 -07005171 mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex);
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05305172 mutex_init(&ipa3_ctx->ipa_cne_evt_lock);
Mohammed Javid05b05d02017-11-13 23:43:27 +05305173 ipa3_ctx->q6_proxy_clk_vote_cnt = 0;
Amir Levy9659e592016-10-27 18:08:27 +03005174
5175 idr_init(&ipa3_ctx->ipa_idr);
5176 spin_lock_init(&ipa3_ctx->idr_lock);
5177
5178 /* wlan related member */
5179 memset(&ipa3_ctx->wc_memb, 0, sizeof(ipa3_ctx->wc_memb));
5180 spin_lock_init(&ipa3_ctx->wc_memb.wlan_spinlock);
5181 spin_lock_init(&ipa3_ctx->wc_memb.ipa_tx_mul_spinlock);
5182 INIT_LIST_HEAD(&ipa3_ctx->wc_memb.wlan_comm_desc_list);
5183
Amir Levy9659e592016-10-27 18:08:27 +03005184 ipa3_ctx->class = class_create(THIS_MODULE, DRV_NAME);
5185
5186 result = alloc_chrdev_region(&ipa3_ctx->dev_num, 0, 1, DRV_NAME);
5187 if (result) {
5188 IPAERR("alloc_chrdev_region err.\n");
5189 result = -ENODEV;
5190 goto fail_alloc_chrdev_region;
5191 }
5192
5193 ipa3_ctx->dev = device_create(ipa3_ctx->class, NULL, ipa3_ctx->dev_num,
5194 ipa3_ctx, DRV_NAME);
5195 if (IS_ERR(ipa3_ctx->dev)) {
5196 IPAERR(":device_create err.\n");
5197 result = -ENODEV;
5198 goto fail_device_create;
5199 }
5200
Amir Levy479cfdd2017-10-26 12:23:14 +03005201 if (ipa3_nat_ipv6ct_init_devices()) {
5202 IPAERR("unable to init NAT and IPv6CT devices\n");
Amir Levy9659e592016-10-27 18:08:27 +03005203 result = -ENODEV;
Amir Levy479cfdd2017-10-26 12:23:14 +03005204 goto fail_nat_ipv6ct_init_dev;
Amir Levy9659e592016-10-27 18:08:27 +03005205 }
5206
5207 /* Create a wakeup source. */
5208 wakeup_source_init(&ipa3_ctx->w_lock, "IPA_WS");
5209 spin_lock_init(&ipa3_ctx->wakelock_ref_cnt.spinlock);
5210
Michael Adisumarta3e350812017-09-18 14:54:36 -07005211 /* Initialize Power Management framework */
5212 if (ipa3_ctx->use_ipa_pm) {
5213 result = ipa_pm_init(&ipa3_res.pm_init);
5214 if (result) {
5215 IPAERR("IPA PM initialization failed (%d)\n", -result);
5216 result = -ENODEV;
5217 goto fail_ipa_rm_init;
5218 }
5219 IPADBG("IPA resource manager initialized");
5220 } else {
5221 result = ipa_rm_initialize();
5222 if (result) {
5223 IPAERR("RM initialization failed (%d)\n", -result);
5224 result = -ENODEV;
5225 goto fail_ipa_rm_init;
5226 }
5227 IPADBG("IPA resource manager initialized");
Amir Levy9659e592016-10-27 18:08:27 +03005228
Michael Adisumarta3e350812017-09-18 14:54:36 -07005229 result = ipa3_create_apps_resource();
5230 if (result) {
5231 IPAERR("Failed to create APPS_CONS resource\n");
5232 result = -ENODEV;
5233 goto fail_create_apps_resource;
5234 }
Amir Levy9659e592016-10-27 18:08:27 +03005235 }
5236
Skylar Changcd3902d2017-03-27 18:08:27 -07005237 result = ipa3_alloc_pkt_init();
5238 if (result) {
5239 IPAERR("Failed to alloc pkt_init payload\n");
5240 result = -ENODEV;
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005241 goto fail_allok_pkt_init;
Skylar Changcd3902d2017-03-27 18:08:27 -07005242 }
5243
Amir Levy12ef0912016-08-30 09:27:34 +03005244 if (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5)
5245 ipa3_enable_dcd();
5246
Amir Levy9659e592016-10-27 18:08:27 +03005247 INIT_LIST_HEAD(&ipa3_ctx->ipa_ready_cb_list);
5248
5249 init_completion(&ipa3_ctx->init_completion_obj);
Skylar Chang0c17c7d2016-10-31 09:57:54 -07005250 init_completion(&ipa3_ctx->uc_loaded_completion_obj);
Amir Levy9659e592016-10-27 18:08:27 +03005251
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005252 result = ipa3_dma_setup();
5253 if (result) {
5254 IPAERR("Failed to setup IPA DMA\n");
5255 result = -ENODEV;
5256 goto fail_ipa_dma_setup;
5257 }
5258
Amir Levy9659e592016-10-27 18:08:27 +03005259 /*
Amir Levya59ed3f2017-03-05 17:30:55 +02005260 * We can't register the GSI driver yet, as it expects
Amir Levy9659e592016-10-27 18:08:27 +03005261 * the GSI FW to be up and running before the registration.
Amir Levya59ed3f2017-03-05 17:30:55 +02005262 *
5263 * For IPA3.0, the GSI configuration is done by the GSI driver.
5264 * For IPA3.1 (and on), the GSI configuration is done by TZ.
Amir Levy9659e592016-10-27 18:08:27 +03005265 */
Amir Levya59ed3f2017-03-05 17:30:55 +02005266 if (ipa3_ctx->ipa_hw_type == IPA_HW_v3_0) {
5267 result = ipa3_gsi_pre_fw_load_init();
5268 if (result) {
5269 IPAERR("gsi pre FW loading config failed\n");
5270 result = -ENODEV;
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005271 goto fail_gsi_pre_fw_load_init;
Amir Levy9659e592016-10-27 18:08:27 +03005272 }
5273 }
Amir Levy9659e592016-10-27 18:08:27 +03005274
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305275 cdev_init(&ipa3_ctx->cdev, &ipa3_drv_fops);
5276 ipa3_ctx->cdev.owner = THIS_MODULE;
5277 ipa3_ctx->cdev.ops = &ipa3_drv_fops; /* from LDD3 */
5278
5279 result = cdev_add(&ipa3_ctx->cdev, ipa3_ctx->dev_num, 1);
5280 if (result) {
5281 IPAERR(":cdev_add err=%d\n", -result);
5282 result = -ENODEV;
5283 goto fail_cdev_add;
5284 }
5285 IPADBG("ipa cdev added successful. major:%d minor:%d\n",
5286 MAJOR(ipa3_ctx->dev_num),
5287 MINOR(ipa3_ctx->dev_num));
Amir Levy9659e592016-10-27 18:08:27 +03005288 return 0;
5289
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305290fail_cdev_add:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005291fail_gsi_pre_fw_load_init:
5292 ipa3_dma_shutdown();
5293fail_ipa_dma_setup:
5294fail_allok_pkt_init:
5295 if (ipa3_ctx->use_ipa_pm)
5296 ipa_pm_destroy();
5297 else
Michael Adisumarta3e350812017-09-18 14:54:36 -07005298 ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
Amir Levy9659e592016-10-27 18:08:27 +03005299fail_create_apps_resource:
Michael Adisumarta3e350812017-09-18 14:54:36 -07005300 if (!ipa3_ctx->use_ipa_pm)
5301 ipa_rm_exit();
Amir Levy9659e592016-10-27 18:08:27 +03005302fail_ipa_rm_init:
Amir Levy479cfdd2017-10-26 12:23:14 +03005303 ipa3_nat_ipv6ct_destroy_devices();
5304fail_nat_ipv6ct_init_dev:
Amir Levy9659e592016-10-27 18:08:27 +03005305 device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
5306fail_device_create:
5307 unregister_chrdev_region(ipa3_ctx->dev_num, 1);
5308fail_alloc_chrdev_region:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005309 idr_destroy(&ipa3_ctx->ipa_idr);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005310 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
5311 idr_destroy(&rset->rule_ids);
5312 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
5313 idr_destroy(&rset->rule_ids);
5314 idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
5315 idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
Skylar Chang6c4bec92017-04-21 16:10:14 -07005316 ipa3_free_dma_task_for_gsi();
5317fail_dma_task:
Amir Levy9659e592016-10-27 18:08:27 +03005318 kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
5319fail_rx_pkt_wrapper_cache:
5320 kmem_cache_destroy(ipa3_ctx->tx_pkt_wrapper_cache);
5321fail_tx_pkt_wrapper_cache:
5322 kmem_cache_destroy(ipa3_ctx->rt_tbl_cache);
5323fail_rt_tbl_cache:
5324 kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_offset_cache);
5325fail_hdr_proc_ctx_offset_cache:
5326 kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_cache);
5327fail_hdr_proc_ctx_cache:
5328 kmem_cache_destroy(ipa3_ctx->hdr_offset_cache);
5329fail_hdr_offset_cache:
5330 kmem_cache_destroy(ipa3_ctx->hdr_cache);
5331fail_hdr_cache:
5332 kmem_cache_destroy(ipa3_ctx->rt_rule_cache);
5333fail_rt_rule_cache:
5334 kmem_cache_destroy(ipa3_ctx->flt_rule_cache);
5335fail_flt_rule_cache:
5336 destroy_workqueue(ipa3_ctx->transport_power_mgmt_wq);
5337fail_create_transport_wq:
5338 destroy_workqueue(ipa3_ctx->power_mgmt_wq);
5339fail_init_hw:
5340 ipahal_destroy();
5341fail_ipahal:
5342 iounmap(ipa3_ctx->mmio);
5343fail_remap:
5344 ipa3_disable_clks();
5345 ipa3_active_clients_log_destroy();
5346fail_init_active_client:
Ghanim Fodi6a831342017-03-07 18:19:15 +02005347 if (ipa3_clk)
5348 clk_put(ipa3_clk);
5349 ipa3_clk = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03005350fail_clk:
5351 msm_bus_scale_unregister_client(ipa3_ctx->ipa_bus_hdl);
5352fail_bus_reg:
Ghanim Fodi6a831342017-03-07 18:19:15 +02005353 if (ipa3_bus_scale_table) {
5354 msm_bus_cl_clear_pdata(ipa3_bus_scale_table);
5355 ipa3_bus_scale_table = NULL;
5356 }
Amir Levy9659e592016-10-27 18:08:27 +03005357fail_init_mem_partition:
5358fail_bind:
5359 kfree(ipa3_ctx->ctrl);
5360fail_mem_ctrl:
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005361 kfree(ipa3_ctx->ipa_tz_unlock_reg);
5362fail_tz_unlock_reg:
Skylar Chang841c1452017-04-03 16:07:22 -07005363 if (ipa3_ctx->logbuf)
5364 ipc_log_context_destroy(ipa3_ctx->logbuf);
Amir Levy9659e592016-10-27 18:08:27 +03005365 kfree(ipa3_ctx);
5366 ipa3_ctx = NULL;
5367fail_mem_ctx:
5368 return result;
5369}
5370
Michael Adisumarta3e350812017-09-18 14:54:36 -07005371bool ipa_pm_is_used(void)
5372{
5373 return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
5374}
5375
5376static int get_ipa_dts_pm_info(struct platform_device *pdev,
5377 struct ipa3_plat_drv_res *ipa_drv_res)
5378{
5379 int result;
5380 int i, j;
5381
5382 ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
5383 "qcom,use-ipa-pm");
5384 IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
5385 if (!ipa_drv_res->use_ipa_pm)
5386 return 0;
5387
5388 result = of_property_read_u32(pdev->dev.of_node,
5389 "qcom,msm-bus,num-cases",
5390 &ipa_drv_res->pm_init.threshold_size);
5391 /* No vote is ignored */
5392 ipa_drv_res->pm_init.threshold_size -= 2;
5393 if (result || ipa_drv_res->pm_init.threshold_size >
5394 IPA_PM_THRESHOLD_MAX) {
5395 IPAERR("invalid property qcom,msm-bus,num-cases %d\n",
5396 ipa_drv_res->pm_init.threshold_size);
5397 return -EFAULT;
5398 }
5399
5400 result = of_property_read_u32_array(pdev->dev.of_node,
5401 "qcom,throughput-threshold",
5402 ipa_drv_res->pm_init.default_threshold,
5403 ipa_drv_res->pm_init.threshold_size);
5404 if (result) {
5405 IPAERR("failed to read qcom,throughput-thresholds\n");
5406 return -EFAULT;
5407 }
5408
5409 result = of_property_count_strings(pdev->dev.of_node,
5410 "qcom,scaling-exceptions");
5411 if (result < 0) {
5412 IPADBG("no exception list for ipa pm\n");
5413 result = 0;
5414 }
5415
5416 if (result % (ipa_drv_res->pm_init.threshold_size + 1)) {
5417 IPAERR("failed to read qcom,scaling-exceptions\n");
5418 return -EFAULT;
5419 }
5420
5421 ipa_drv_res->pm_init.exception_size = result /
5422 (ipa_drv_res->pm_init.threshold_size + 1);
5423 if (ipa_drv_res->pm_init.exception_size >=
5424 IPA_PM_EXCEPTION_MAX) {
5425 IPAERR("exception list larger then max %d\n",
5426 ipa_drv_res->pm_init.exception_size);
5427 return -EFAULT;
5428 }
5429
5430 for (i = 0; i < ipa_drv_res->pm_init.exception_size; i++) {
5431 struct ipa_pm_exception *ex = ipa_drv_res->pm_init.exceptions;
5432
5433 result = of_property_read_string_index(pdev->dev.of_node,
5434 "qcom,scaling-exceptions",
5435 i * ipa_drv_res->pm_init.threshold_size,
5436 &ex[i].usecase);
5437 if (result) {
5438 IPAERR("failed to read qcom,scaling-exceptions");
5439 return -EFAULT;
5440 }
5441
5442 for (j = 0; j < ipa_drv_res->pm_init.threshold_size; j++) {
5443 const char *str;
5444
5445 result = of_property_read_string_index(
5446 pdev->dev.of_node,
5447 "qcom,scaling-exceptions",
5448 i * ipa_drv_res->pm_init.threshold_size + j + 1,
5449 &str);
5450 if (result) {
5451 IPAERR("failed to read qcom,scaling-exceptions"
5452 );
5453 return -EFAULT;
5454 }
5455
5456 if (kstrtou32(str, 0, &ex[i].threshold[j])) {
5457 IPAERR("error str=%s\n", str);
5458 return -EFAULT;
5459 }
5460 }
5461 }
5462
5463 return 0;
5464}
5465
Amir Levy9659e592016-10-27 18:08:27 +03005466static int get_ipa_dts_configuration(struct platform_device *pdev,
5467 struct ipa3_plat_drv_res *ipa_drv_res)
5468{
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005469 int i, result, pos;
Amir Levy9659e592016-10-27 18:08:27 +03005470 struct resource *resource;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005471 u32 *ipa_tz_unlock_reg;
5472 int elem_num;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005473 u32 mhi_evid_limits[2];
Amir Levy9659e592016-10-27 18:08:27 +03005474
5475 /* initialize ipa3_res */
5476 ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
5477 ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
5478 ipa_drv_res->ipa_hw_type = 0;
5479 ipa_drv_res->ipa3_hw_mode = 0;
Amir Levy9659e592016-10-27 18:08:27 +03005480 ipa_drv_res->modem_cfg_emb_pipe_flt = false;
5481 ipa_drv_res->ipa_wdi2 = false;
5482 ipa_drv_res->use_64_bit_dma_mask = false;
Ghanim Fodi6a831342017-03-07 18:19:15 +02005483 ipa_drv_res->use_bw_vote = false;
Amir Levy9659e592016-10-27 18:08:27 +03005484 ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
5485 ipa_drv_res->lan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
5486 ipa_drv_res->apply_rg10_wa = false;
5487 ipa_drv_res->gsi_ch20_wa = false;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005488 ipa_drv_res->ipa_tz_unlock_reg_num = 0;
5489 ipa_drv_res->ipa_tz_unlock_reg = NULL;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005490 ipa_drv_res->mhi_evid_limits[0] = IPA_MHI_GSI_EVENT_RING_ID_START;
5491 ipa_drv_res->mhi_evid_limits[1] = IPA_MHI_GSI_EVENT_RING_ID_END;
Amir Levy9659e592016-10-27 18:08:27 +03005492
5493 /* Get IPA HW Version */
5494 result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver",
5495 &ipa_drv_res->ipa_hw_type);
5496 if ((result) || (ipa_drv_res->ipa_hw_type == 0)) {
5497 IPAERR(":get resource failed for ipa-hw-ver!\n");
5498 return -ENODEV;
5499 }
5500 IPADBG(": ipa_hw_type = %d", ipa_drv_res->ipa_hw_type);
5501
5502 if (ipa_drv_res->ipa_hw_type < IPA_HW_v3_0) {
5503 IPAERR(":IPA version below 3.0 not supported!\n");
5504 return -ENODEV;
5505 }
5506
5507 /* Get IPA HW mode */
5508 result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-mode",
5509 &ipa_drv_res->ipa3_hw_mode);
5510 if (result)
5511 IPADBG("using default (IPA_MODE_NORMAL) for ipa-hw-mode\n");
5512 else
5513 IPADBG(": found ipa_drv_res->ipa3_hw_mode = %d",
5514 ipa_drv_res->ipa3_hw_mode);
5515
5516 /* Get IPA WAN / LAN RX pool size */
5517 result = of_property_read_u32(pdev->dev.of_node,
5518 "qcom,wan-rx-ring-size",
5519 &ipa_drv_res->wan_rx_ring_size);
5520 if (result)
5521 IPADBG("using default for wan-rx-ring-size = %u\n",
5522 ipa_drv_res->wan_rx_ring_size);
5523 else
5524 IPADBG(": found ipa_drv_res->wan-rx-ring-size = %u",
5525 ipa_drv_res->wan_rx_ring_size);
5526
5527 result = of_property_read_u32(pdev->dev.of_node,
5528 "qcom,lan-rx-ring-size",
5529 &ipa_drv_res->lan_rx_ring_size);
5530 if (result)
5531 IPADBG("using default for lan-rx-ring-size = %u\n",
5532 ipa_drv_res->lan_rx_ring_size);
5533 else
5534 IPADBG(": found ipa_drv_res->lan-rx-ring-size = %u",
5535 ipa_drv_res->lan_rx_ring_size);
5536
5537 ipa_drv_res->use_ipa_teth_bridge =
5538 of_property_read_bool(pdev->dev.of_node,
5539 "qcom,use-ipa-tethering-bridge");
5540 IPADBG(": using TBDr = %s",
5541 ipa_drv_res->use_ipa_teth_bridge
5542 ? "True" : "False");
5543
Amir Levy9659e592016-10-27 18:08:27 +03005544 ipa_drv_res->modem_cfg_emb_pipe_flt =
5545 of_property_read_bool(pdev->dev.of_node,
5546 "qcom,modem-cfg-emb-pipe-flt");
5547 IPADBG(": modem configure embedded pipe filtering = %s\n",
5548 ipa_drv_res->modem_cfg_emb_pipe_flt
5549 ? "True" : "False");
5550
5551 ipa_drv_res->ipa_wdi2 =
5552 of_property_read_bool(pdev->dev.of_node,
5553 "qcom,ipa-wdi2");
5554 IPADBG(": WDI-2.0 = %s\n",
5555 ipa_drv_res->ipa_wdi2
5556 ? "True" : "False");
5557
5558 ipa_drv_res->use_64_bit_dma_mask =
5559 of_property_read_bool(pdev->dev.of_node,
5560 "qcom,use-64-bit-dma-mask");
5561 IPADBG(": use_64_bit_dma_mask = %s\n",
5562 ipa_drv_res->use_64_bit_dma_mask
5563 ? "True" : "False");
5564
Ghanim Fodi6a831342017-03-07 18:19:15 +02005565 ipa_drv_res->use_bw_vote =
5566 of_property_read_bool(pdev->dev.of_node,
5567 "qcom,bandwidth-vote-for-ipa");
5568 IPADBG(": use_bw_vote = %s\n",
5569 ipa_drv_res->use_bw_vote
5570 ? "True" : "False");
5571
Amir Levy9659e592016-10-27 18:08:27 +03005572 ipa_drv_res->skip_uc_pipe_reset =
5573 of_property_read_bool(pdev->dev.of_node,
5574 "qcom,skip-uc-pipe-reset");
5575 IPADBG(": skip uC pipe reset = %s\n",
5576 ipa_drv_res->skip_uc_pipe_reset
5577 ? "True" : "False");
5578
5579 ipa_drv_res->tethered_flow_control =
5580 of_property_read_bool(pdev->dev.of_node,
5581 "qcom,tethered-flow-control");
5582 IPADBG(": Use apps based flow control = %s\n",
5583 ipa_drv_res->tethered_flow_control
5584 ? "True" : "False");
5585
Amir Levy9659e592016-10-27 18:08:27 +03005586 /* Get IPA wrapper address */
5587 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5588 "ipa-base");
5589 if (!resource) {
5590 IPAERR(":get resource failed for ipa-base!\n");
5591 return -ENODEV;
5592 }
5593 ipa_drv_res->ipa_mem_base = resource->start;
5594 ipa_drv_res->ipa_mem_size = resource_size(resource);
5595 IPADBG(": ipa-base = 0x%x, size = 0x%x\n",
5596 ipa_drv_res->ipa_mem_base,
5597 ipa_drv_res->ipa_mem_size);
5598
5599 smmu_info.ipa_base = ipa_drv_res->ipa_mem_base;
5600 smmu_info.ipa_size = ipa_drv_res->ipa_mem_size;
5601
Amir Levya59ed3f2017-03-05 17:30:55 +02005602 /* Get IPA GSI address */
5603 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5604 "gsi-base");
5605 if (!resource) {
5606 IPAERR(":get resource failed for gsi-base!\n");
5607 return -ENODEV;
Amir Levy9659e592016-10-27 18:08:27 +03005608 }
Amir Levya59ed3f2017-03-05 17:30:55 +02005609 ipa_drv_res->transport_mem_base = resource->start;
5610 ipa_drv_res->transport_mem_size = resource_size(resource);
5611 IPADBG(": gsi-base = 0x%x, size = 0x%x\n",
5612 ipa_drv_res->transport_mem_base,
5613 ipa_drv_res->transport_mem_size);
5614
5615 /* Get IPA GSI IRQ number */
5616 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
5617 "gsi-irq");
5618 if (!resource) {
5619 IPAERR(":get resource failed for gsi-irq!\n");
5620 return -ENODEV;
5621 }
5622 ipa_drv_res->transport_irq = resource->start;
5623 IPADBG(": gsi-irq = %d\n", ipa_drv_res->transport_irq);
Amir Levy9659e592016-10-27 18:08:27 +03005624
5625 /* Get IPA pipe mem start ofst */
5626 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5627 "ipa-pipe-mem");
5628 if (!resource) {
5629 IPADBG(":not using pipe memory - resource nonexisting\n");
5630 } else {
5631 ipa_drv_res->ipa_pipe_mem_start_ofst = resource->start;
5632 ipa_drv_res->ipa_pipe_mem_size = resource_size(resource);
5633 IPADBG(":using pipe memory - at 0x%x of size 0x%x\n",
5634 ipa_drv_res->ipa_pipe_mem_start_ofst,
5635 ipa_drv_res->ipa_pipe_mem_size);
5636 }
5637
5638 /* Get IPA IRQ number */
5639 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
5640 "ipa-irq");
5641 if (!resource) {
5642 IPAERR(":get resource failed for ipa-irq!\n");
5643 return -ENODEV;
5644 }
5645 ipa_drv_res->ipa_irq = resource->start;
5646 IPADBG(":ipa-irq = %d\n", ipa_drv_res->ipa_irq);
5647
5648 result = of_property_read_u32(pdev->dev.of_node, "qcom,ee",
5649 &ipa_drv_res->ee);
5650 if (result)
5651 ipa_drv_res->ee = 0;
5652
5653 ipa_drv_res->apply_rg10_wa =
5654 of_property_read_bool(pdev->dev.of_node,
5655 "qcom,use-rg10-limitation-mitigation");
5656 IPADBG(": Use Register Group 10 limitation mitigation = %s\n",
5657 ipa_drv_res->apply_rg10_wa
5658 ? "True" : "False");
5659
5660 ipa_drv_res->gsi_ch20_wa =
5661 of_property_read_bool(pdev->dev.of_node,
5662 "qcom,do-not-use-ch-gsi-20");
5663 IPADBG(": GSI CH 20 WA is = %s\n",
5664 ipa_drv_res->apply_rg10_wa
5665 ? "Needed" : "Not needed");
5666
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005667 elem_num = of_property_count_elems_of_size(pdev->dev.of_node,
Ghanim Fodic823bc62017-10-21 17:29:53 +03005668 "qcom,mhi-event-ring-id-limits", sizeof(u32));
5669
5670 if (elem_num == 2) {
5671 if (of_property_read_u32_array(pdev->dev.of_node,
5672 "qcom,mhi-event-ring-id-limits", mhi_evid_limits, 2)) {
5673 IPAERR("failed to read mhi event ring id limits\n");
5674 return -EFAULT;
5675 }
5676 if (mhi_evid_limits[0] > mhi_evid_limits[1]) {
5677 IPAERR("mhi event ring id low limit > high limit\n");
5678 return -EFAULT;
5679 }
5680 ipa_drv_res->mhi_evid_limits[0] = mhi_evid_limits[0];
5681 ipa_drv_res->mhi_evid_limits[1] = mhi_evid_limits[1];
5682 IPADBG(": mhi-event-ring-id-limits start=%u end=%u\n",
5683 mhi_evid_limits[0], mhi_evid_limits[1]);
5684 } else {
5685 if (elem_num > 0) {
5686 IPAERR("Invalid mhi event ring id limits number %d\n",
5687 elem_num);
5688 return -EINVAL;
5689 }
5690 IPADBG("use default mhi evt ring id limits start=%u end=%u\n",
5691 ipa_drv_res->mhi_evid_limits[0],
5692 ipa_drv_res->mhi_evid_limits[1]);
5693 }
5694
5695 elem_num = of_property_count_elems_of_size(pdev->dev.of_node,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005696 "qcom,ipa-tz-unlock-reg", sizeof(u32));
5697
5698 if (elem_num > 0 && elem_num % 2 == 0) {
5699 ipa_drv_res->ipa_tz_unlock_reg_num = elem_num / 2;
5700
5701 ipa_tz_unlock_reg = kcalloc(elem_num, sizeof(u32), GFP_KERNEL);
5702 if (ipa_tz_unlock_reg == NULL)
5703 return -ENOMEM;
5704
5705 ipa_drv_res->ipa_tz_unlock_reg = kcalloc(
5706 ipa_drv_res->ipa_tz_unlock_reg_num,
5707 sizeof(*ipa_drv_res->ipa_tz_unlock_reg),
5708 GFP_KERNEL);
5709 if (ipa_drv_res->ipa_tz_unlock_reg == NULL) {
5710 kfree(ipa_tz_unlock_reg);
5711 return -ENOMEM;
5712 }
5713
5714 if (of_property_read_u32_array(pdev->dev.of_node,
5715 "qcom,ipa-tz-unlock-reg", ipa_tz_unlock_reg,
5716 elem_num)) {
5717 IPAERR("failed to read register addresses\n");
5718 kfree(ipa_tz_unlock_reg);
5719 kfree(ipa_drv_res->ipa_tz_unlock_reg);
5720 return -EFAULT;
5721 }
5722
5723 pos = 0;
5724 for (i = 0; i < ipa_drv_res->ipa_tz_unlock_reg_num; i++) {
5725 ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr =
5726 ipa_tz_unlock_reg[pos++];
5727 ipa_drv_res->ipa_tz_unlock_reg[i].size =
5728 ipa_tz_unlock_reg[pos++];
Skylar Chang48afa052017-10-25 09:32:57 -07005729 IPADBG("tz unlock reg %d: addr 0x%pa size %llu\n", i,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005730 &ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr,
5731 ipa_drv_res->ipa_tz_unlock_reg[i].size);
5732 }
5733 kfree(ipa_tz_unlock_reg);
5734 }
Michael Adisumarta3e350812017-09-18 14:54:36 -07005735
5736 /* get IPA PM related information */
5737 result = get_ipa_dts_pm_info(pdev, ipa_drv_res);
5738 if (result) {
5739 IPAERR("failed to get pm info from dts %d\n", result);
5740 return result;
5741 }
5742
Amir Levy9659e592016-10-27 18:08:27 +03005743 return 0;
5744}
5745
5746static int ipa_smmu_wlan_cb_probe(struct device *dev)
5747{
5748 struct ipa_smmu_cb_ctx *cb = ipa3_get_wlan_smmu_ctx();
Amir Levy9659e592016-10-27 18:08:27 +03005749 int atomic_ctx = 1;
5750 int fast = 1;
5751 int bypass = 1;
5752 int ret;
5753 u32 add_map_size;
5754 const u32 *add_map;
5755 int i;
5756
5757 IPADBG("sub pdev=%p\n", dev);
5758
5759 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02005760 cb->iommu = iommu_domain_alloc(dev->bus);
Amir Levy9659e592016-10-27 18:08:27 +03005761 if (!cb->iommu) {
5762 IPAERR("could not alloc iommu domain\n");
5763 /* assume this failure is because iommu driver is not ready */
5764 return -EPROBE_DEFER;
5765 }
5766 cb->valid = true;
5767
Michael Adisumarta93e97522017-10-06 15:49:46 -07005768 if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass")) {
5769 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = true;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005770 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN] = true;
5771
Amir Levy9659e592016-10-27 18:08:27 +03005772 if (iommu_domain_set_attr(cb->iommu,
5773 DOMAIN_ATTR_S1_BYPASS,
5774 &bypass)) {
5775 IPAERR("couldn't set bypass\n");
5776 cb->valid = false;
5777 return -EIO;
5778 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07005779 IPADBG("WLAN SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03005780 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07005781 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = false;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005782 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN] = false;
5783
Amir Levy9659e592016-10-27 18:08:27 +03005784 if (iommu_domain_set_attr(cb->iommu,
5785 DOMAIN_ATTR_ATOMIC,
5786 &atomic_ctx)) {
5787 IPAERR("couldn't disable coherent HTW\n");
5788 cb->valid = false;
5789 return -EIO;
5790 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07005791 IPADBG(" WLAN SMMU ATTR ATOMIC\n");
Amir Levy9659e592016-10-27 18:08:27 +03005792
5793 if (smmu_info.fast_map) {
5794 if (iommu_domain_set_attr(cb->iommu,
5795 DOMAIN_ATTR_FAST,
5796 &fast)) {
5797 IPAERR("couldn't set fast map\n");
5798 cb->valid = false;
5799 return -EIO;
5800 }
5801 IPADBG("SMMU fast map set\n");
5802 }
5803 }
5804
Michael Adisumarta93e97522017-10-06 15:49:46 -07005805 pr_info("IPA smmu_info.s1_bypass_arr[WLAN]=%d smmu_info.fast_map=%d\n",
5806 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN], smmu_info.fast_map);
5807
Amir Levy9659e592016-10-27 18:08:27 +03005808 ret = iommu_attach_device(cb->iommu, dev);
5809 if (ret) {
5810 IPAERR("could not attach device ret=%d\n", ret);
5811 cb->valid = false;
5812 return ret;
5813 }
5814 /* MAP ipa-uc ram */
5815 add_map = of_get_property(dev->of_node,
5816 "qcom,additional-mapping", &add_map_size);
5817 if (add_map) {
5818 /* mapping size is an array of 3-tuple of u32 */
5819 if (add_map_size % (3 * sizeof(u32))) {
5820 IPAERR("wrong additional mapping format\n");
5821 cb->valid = false;
5822 return -EFAULT;
5823 }
5824
5825 /* iterate of each entry of the additional mapping array */
5826 for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
5827 u32 iova = be32_to_cpu(add_map[i]);
5828 u32 pa = be32_to_cpu(add_map[i + 1]);
5829 u32 size = be32_to_cpu(add_map[i + 2]);
5830 unsigned long iova_p;
5831 phys_addr_t pa_p;
5832 u32 size_p;
5833
5834 IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
5835 iova_p, pa_p, size_p);
5836 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
5837 iova_p, &pa_p, size_p);
5838 ipa3_iommu_map(cb->iommu,
5839 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02005840 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03005841 }
5842 }
5843 return 0;
5844}
5845
5846static int ipa_smmu_uc_cb_probe(struct device *dev)
5847{
5848 struct ipa_smmu_cb_ctx *cb = ipa3_get_uc_smmu_ctx();
Amir Levy9659e592016-10-27 18:08:27 +03005849 int atomic_ctx = 1;
5850 int bypass = 1;
5851 int fast = 1;
5852 int ret;
5853 u32 iova_ap_mapping[2];
5854
5855 IPADBG("UC CB PROBE sub pdev=%p\n", dev);
5856
5857 ret = of_property_read_u32_array(dev->of_node, "qcom,iova-mapping",
5858 iova_ap_mapping, 2);
5859 if (ret) {
5860 IPAERR("Fail to read UC start/size iova addresses\n");
5861 return ret;
5862 }
5863 cb->va_start = iova_ap_mapping[0];
5864 cb->va_size = iova_ap_mapping[1];
5865 cb->va_end = cb->va_start + cb->va_size;
5866 IPADBG("UC va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
5867
5868 if (smmu_info.use_64_bit_dma_mask) {
5869 if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
5870 dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
5871 IPAERR("DMA set 64bit mask failed\n");
5872 return -EOPNOTSUPP;
5873 }
5874 } else {
5875 if (dma_set_mask(dev, DMA_BIT_MASK(32)) ||
5876 dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
5877 IPAERR("DMA set 32bit mask failed\n");
5878 return -EOPNOTSUPP;
5879 }
5880 }
5881 IPADBG("UC CB PROBE=%p create IOMMU mapping\n", dev);
5882
5883 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02005884 cb->mapping = arm_iommu_create_mapping(dev->bus,
Amir Levy9659e592016-10-27 18:08:27 +03005885 cb->va_start, cb->va_size);
5886 if (IS_ERR_OR_NULL(cb->mapping)) {
5887 IPADBG("Fail to create mapping\n");
5888 /* assume this failure is because iommu driver is not ready */
5889 return -EPROBE_DEFER;
5890 }
5891 IPADBG("SMMU mapping created\n");
5892 cb->valid = true;
5893
Amir Levy9659e592016-10-27 18:08:27 +03005894 IPADBG("UC CB PROBE sub pdev=%p set attribute\n", dev);
Michael Adisumarta93e97522017-10-06 15:49:46 -07005895
5896 if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass")) {
5897 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC] = true;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005898 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = true;
5899
Amir Levy9659e592016-10-27 18:08:27 +03005900 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07005901 DOMAIN_ATTR_S1_BYPASS,
5902 &bypass)) {
Amir Levy9659e592016-10-27 18:08:27 +03005903 IPAERR("couldn't set bypass\n");
5904 arm_iommu_release_mapping(cb->mapping);
5905 cb->valid = false;
5906 return -EIO;
5907 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07005908 IPADBG("UC SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03005909 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07005910 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC] = false;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005911 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = false;
5912
Amir Levy9659e592016-10-27 18:08:27 +03005913 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07005914 DOMAIN_ATTR_ATOMIC,
5915 &atomic_ctx)) {
Amir Levy9659e592016-10-27 18:08:27 +03005916 IPAERR("couldn't set domain as atomic\n");
5917 arm_iommu_release_mapping(cb->mapping);
5918 cb->valid = false;
5919 return -EIO;
5920 }
5921 IPADBG("SMMU atomic set\n");
5922
5923 if (smmu_info.fast_map) {
5924 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07005925 DOMAIN_ATTR_FAST,
5926 &fast)) {
Amir Levy9659e592016-10-27 18:08:27 +03005927 IPAERR("couldn't set fast map\n");
5928 arm_iommu_release_mapping(cb->mapping);
5929 cb->valid = false;
5930 return -EIO;
5931 }
5932 IPADBG("SMMU fast map set\n");
5933 }
5934 }
5935
Michael Adisumarta93e97522017-10-06 15:49:46 -07005936 pr_info("IPA smmu_info.s1_bypass_arr[UC]=%d smmu_info.fast_map=%d\n",
5937 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC], smmu_info.fast_map);
5938
Amir Levy9659e592016-10-27 18:08:27 +03005939 IPADBG("UC CB PROBE sub pdev=%p attaching IOMMU device\n", dev);
5940 ret = arm_iommu_attach_device(cb->dev, cb->mapping);
5941 if (ret) {
5942 IPAERR("could not attach device ret=%d\n", ret);
5943 arm_iommu_release_mapping(cb->mapping);
5944 cb->valid = false;
5945 return ret;
5946 }
5947
5948 cb->next_addr = cb->va_end;
5949 ipa3_ctx->uc_pdev = dev;
5950
5951 return 0;
5952}
5953
5954static int ipa_smmu_ap_cb_probe(struct device *dev)
5955{
5956 struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx();
5957 int result;
Amir Levy9659e592016-10-27 18:08:27 +03005958 int atomic_ctx = 1;
5959 int fast = 1;
5960 int bypass = 1;
5961 u32 iova_ap_mapping[2];
5962 u32 add_map_size;
5963 const u32 *add_map;
5964 void *smem_addr;
5965 int i;
5966
5967 IPADBG("AP CB probe: sub pdev=%p\n", dev);
5968
5969 result = of_property_read_u32_array(dev->of_node, "qcom,iova-mapping",
5970 iova_ap_mapping, 2);
5971 if (result) {
5972 IPAERR("Fail to read AP start/size iova addresses\n");
5973 return result;
5974 }
5975 cb->va_start = iova_ap_mapping[0];
5976 cb->va_size = iova_ap_mapping[1];
5977 cb->va_end = cb->va_start + cb->va_size;
5978 IPADBG("AP va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
5979
5980 if (smmu_info.use_64_bit_dma_mask) {
5981 if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
5982 dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
5983 IPAERR("DMA set 64bit mask failed\n");
5984 return -EOPNOTSUPP;
5985 }
5986 } else {
5987 if (dma_set_mask(dev, DMA_BIT_MASK(32)) ||
5988 dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
5989 IPAERR("DMA set 32bit mask failed\n");
5990 return -EOPNOTSUPP;
5991 }
5992 }
5993
5994 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02005995 cb->mapping = arm_iommu_create_mapping(dev->bus,
Amir Levy9659e592016-10-27 18:08:27 +03005996 cb->va_start, cb->va_size);
5997 if (IS_ERR_OR_NULL(cb->mapping)) {
5998 IPADBG("Fail to create mapping\n");
5999 /* assume this failure is because iommu driver is not ready */
6000 return -EPROBE_DEFER;
6001 }
6002 IPADBG("SMMU mapping created\n");
6003 cb->valid = true;
6004
Michael Adisumarta93e97522017-10-06 15:49:46 -07006005 if (of_property_read_bool(dev->of_node,
6006 "qcom,smmu-s1-bypass")) {
6007 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP] = true;
Amir Levy9659e592016-10-27 18:08:27 +03006008 if (iommu_domain_set_attr(cb->mapping->domain,
6009 DOMAIN_ATTR_S1_BYPASS,
6010 &bypass)) {
6011 IPAERR("couldn't set bypass\n");
6012 arm_iommu_release_mapping(cb->mapping);
6013 cb->valid = false;
6014 return -EIO;
6015 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006016 IPADBG("AP/USB SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03006017 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006018 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP] = false;
Amir Levy9659e592016-10-27 18:08:27 +03006019 if (iommu_domain_set_attr(cb->mapping->domain,
6020 DOMAIN_ATTR_ATOMIC,
6021 &atomic_ctx)) {
6022 IPAERR("couldn't set domain as atomic\n");
6023 arm_iommu_release_mapping(cb->mapping);
6024 cb->valid = false;
6025 return -EIO;
6026 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006027 IPADBG("AP/USB SMMU atomic set\n");
Amir Levy9659e592016-10-27 18:08:27 +03006028
6029 if (iommu_domain_set_attr(cb->mapping->domain,
6030 DOMAIN_ATTR_FAST,
6031 &fast)) {
6032 IPAERR("couldn't set fast map\n");
6033 arm_iommu_release_mapping(cb->mapping);
6034 cb->valid = false;
6035 return -EIO;
6036 }
6037 IPADBG("SMMU fast map set\n");
6038 }
6039
Michael Adisumarta93e97522017-10-06 15:49:46 -07006040 pr_info("IPA smmu_info.s1_bypass_arr[AP]=%d smmu_info.fast_map=%d\n",
6041 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP], smmu_info.fast_map);
6042
Amir Levy9659e592016-10-27 18:08:27 +03006043 result = arm_iommu_attach_device(cb->dev, cb->mapping);
6044 if (result) {
6045 IPAERR("couldn't attach to IOMMU ret=%d\n", result);
6046 cb->valid = false;
6047 return result;
6048 }
6049
6050 add_map = of_get_property(dev->of_node,
6051 "qcom,additional-mapping", &add_map_size);
6052 if (add_map) {
6053 /* mapping size is an array of 3-tuple of u32 */
6054 if (add_map_size % (3 * sizeof(u32))) {
6055 IPAERR("wrong additional mapping format\n");
6056 cb->valid = false;
6057 return -EFAULT;
6058 }
6059
6060 /* iterate of each entry of the additional mapping array */
6061 for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
6062 u32 iova = be32_to_cpu(add_map[i]);
6063 u32 pa = be32_to_cpu(add_map[i + 1]);
6064 u32 size = be32_to_cpu(add_map[i + 2]);
6065 unsigned long iova_p;
6066 phys_addr_t pa_p;
6067 u32 size_p;
6068
6069 IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
6070 iova_p, pa_p, size_p);
6071 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
6072 iova_p, &pa_p, size_p);
6073 ipa3_iommu_map(cb->mapping->domain,
6074 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02006075 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03006076 }
6077 }
6078
6079 /* map SMEM memory for IPA table accesses */
6080 smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
6081 SMEM_MODEM, 0);
6082 if (smem_addr) {
6083 phys_addr_t iova = smem_virt_to_phys(smem_addr);
6084 phys_addr_t pa = iova;
6085 unsigned long iova_p;
6086 phys_addr_t pa_p;
6087 u32 size_p;
6088
6089 IPA_SMMU_ROUND_TO_PAGE(iova, pa, IPA_SMEM_SIZE,
6090 iova_p, pa_p, size_p);
6091 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
6092 iova_p, &pa_p, size_p);
6093 ipa3_iommu_map(cb->mapping->domain,
6094 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02006095 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03006096 }
6097
6098
6099 smmu_info.present = true;
6100
6101 if (!ipa3_bus_scale_table)
6102 ipa3_bus_scale_table = msm_bus_cl_get_pdata(ipa3_pdev);
6103
6104 /* Proceed to real initialization */
6105 result = ipa3_pre_init(&ipa3_res, dev);
6106 if (result) {
6107 IPAERR("ipa_init failed\n");
6108 arm_iommu_detach_device(cb->dev);
6109 arm_iommu_release_mapping(cb->mapping);
6110 cb->valid = false;
6111 return result;
6112 }
6113
6114 return result;
6115}
6116
6117static irqreturn_t ipa3_smp2p_modem_clk_query_isr(int irq, void *ctxt)
6118{
6119 ipa3_freeze_clock_vote_and_notify_modem();
6120
6121 return IRQ_HANDLED;
6122}
6123
6124static int ipa3_smp2p_probe(struct device *dev)
6125{
6126 struct device_node *node = dev->of_node;
6127 int res;
6128
Mohammed Javid7de12702017-07-21 15:22:58 +05306129 if (ipa3_ctx == NULL) {
6130 IPAERR("ipa3_ctx was not initialized\n");
6131 return -ENXIO;
6132 }
Amir Levy9659e592016-10-27 18:08:27 +03006133 IPADBG("node->name=%s\n", node->name);
6134 if (strcmp("qcom,smp2pgpio_map_ipa_1_out", node->name) == 0) {
6135 res = of_get_gpio(node, 0);
6136 if (res < 0) {
6137 IPADBG("of_get_gpio returned %d\n", res);
6138 return res;
6139 }
6140
6141 ipa3_ctx->smp2p_info.out_base_id = res;
6142 IPADBG("smp2p out_base_id=%d\n",
6143 ipa3_ctx->smp2p_info.out_base_id);
6144 } else if (strcmp("qcom,smp2pgpio_map_ipa_1_in", node->name) == 0) {
6145 int irq;
6146
6147 res = of_get_gpio(node, 0);
6148 if (res < 0) {
6149 IPADBG("of_get_gpio returned %d\n", res);
6150 return res;
6151 }
6152
6153 ipa3_ctx->smp2p_info.in_base_id = res;
6154 IPADBG("smp2p in_base_id=%d\n",
6155 ipa3_ctx->smp2p_info.in_base_id);
6156
6157 /* register for modem clk query */
6158 irq = gpio_to_irq(ipa3_ctx->smp2p_info.in_base_id +
6159 IPA_GPIO_IN_QUERY_CLK_IDX);
6160 if (irq < 0) {
6161 IPAERR("gpio_to_irq failed %d\n", irq);
6162 return -ENODEV;
6163 }
6164 IPADBG("smp2p irq#=%d\n", irq);
6165 res = request_irq(irq,
6166 (irq_handler_t)ipa3_smp2p_modem_clk_query_isr,
6167 IRQF_TRIGGER_RISING, "ipa_smp2p_clk_vote", dev);
6168 if (res) {
6169 IPAERR("fail to register smp2p irq=%d\n", irq);
6170 return -ENODEV;
6171 }
6172 res = enable_irq_wake(ipa3_ctx->smp2p_info.in_base_id +
6173 IPA_GPIO_IN_QUERY_CLK_IDX);
6174 if (res)
6175 IPAERR("failed to enable irq wake\n");
6176 }
6177
6178 return 0;
6179}
6180
6181int ipa3_plat_drv_probe(struct platform_device *pdev_p,
6182 struct ipa_api_controller *api_ctrl,
6183 const struct of_device_id *pdrv_match)
6184{
6185 int result;
6186 struct device *dev = &pdev_p->dev;
6187
6188 IPADBG("IPA driver probing started\n");
6189 IPADBG("dev->of_node->name = %s\n", dev->of_node->name);
6190
6191 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-ap-cb"))
6192 return ipa_smmu_ap_cb_probe(dev);
6193
6194 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-wlan-cb"))
6195 return ipa_smmu_wlan_cb_probe(dev);
6196
6197 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-uc-cb"))
6198 return ipa_smmu_uc_cb_probe(dev);
6199
6200 if (of_device_is_compatible(dev->of_node,
6201 "qcom,smp2pgpio-map-ipa-1-in"))
6202 return ipa3_smp2p_probe(dev);
6203
6204 if (of_device_is_compatible(dev->of_node,
6205 "qcom,smp2pgpio-map-ipa-1-out"))
6206 return ipa3_smp2p_probe(dev);
6207
6208 master_dev = dev;
6209 if (!ipa3_pdev)
6210 ipa3_pdev = pdev_p;
6211
6212 result = get_ipa_dts_configuration(pdev_p, &ipa3_res);
6213 if (result) {
6214 IPAERR("IPA dts parsing failed\n");
6215 return result;
6216 }
6217
6218 result = ipa3_bind_api_controller(ipa3_res.ipa_hw_type, api_ctrl);
6219 if (result) {
6220 IPAERR("IPA API binding failed\n");
6221 return result;
6222 }
6223
Amir Levy9659e592016-10-27 18:08:27 +03006224 if (of_property_read_bool(pdev_p->dev.of_node, "qcom,arm-smmu")) {
6225 if (of_property_read_bool(pdev_p->dev.of_node,
Amir Levy9659e592016-10-27 18:08:27 +03006226 "qcom,smmu-fast-map"))
6227 smmu_info.fast_map = true;
6228 if (of_property_read_bool(pdev_p->dev.of_node,
6229 "qcom,use-64-bit-dma-mask"))
6230 smmu_info.use_64_bit_dma_mask = true;
6231 smmu_info.arm_smmu = true;
Amir Levy9659e592016-10-27 18:08:27 +03006232 } else if (of_property_read_bool(pdev_p->dev.of_node,
6233 "qcom,msm-smmu")) {
6234 IPAERR("Legacy IOMMU not supported\n");
6235 result = -EOPNOTSUPP;
6236 } else {
6237 if (of_property_read_bool(pdev_p->dev.of_node,
6238 "qcom,use-64-bit-dma-mask")) {
6239 if (dma_set_mask(&pdev_p->dev, DMA_BIT_MASK(64)) ||
6240 dma_set_coherent_mask(&pdev_p->dev,
6241 DMA_BIT_MASK(64))) {
6242 IPAERR("DMA set 64bit mask failed\n");
6243 return -EOPNOTSUPP;
6244 }
6245 } else {
6246 if (dma_set_mask(&pdev_p->dev, DMA_BIT_MASK(32)) ||
6247 dma_set_coherent_mask(&pdev_p->dev,
6248 DMA_BIT_MASK(32))) {
6249 IPAERR("DMA set 32bit mask failed\n");
6250 return -EOPNOTSUPP;
6251 }
6252 }
6253
6254 if (!ipa3_bus_scale_table)
6255 ipa3_bus_scale_table = msm_bus_cl_get_pdata(pdev_p);
6256 /* Proceed to real initialization */
6257 result = ipa3_pre_init(&ipa3_res, dev);
6258 if (result) {
6259 IPAERR("ipa3_init failed\n");
6260 return result;
6261 }
6262 }
6263
Ghanim Fodi115bf8a2017-04-21 01:36:06 -07006264 result = of_platform_populate(pdev_p->dev.of_node,
6265 pdrv_match, NULL, &pdev_p->dev);
6266 if (result) {
6267 IPAERR("failed to populate platform\n");
6268 return result;
6269 }
6270
Amir Levy9659e592016-10-27 18:08:27 +03006271 return result;
6272}
6273
6274/**
6275 * ipa3_ap_suspend() - suspend callback for runtime_pm
6276 * @dev: pointer to device
6277 *
6278 * This callback will be invoked by the runtime_pm framework when an AP suspend
6279 * operation is invoked, usually by pressing a suspend button.
6280 *
6281 * Returns -EAGAIN to runtime_pm framework in case IPA is in use by AP.
6282 * This will postpone the suspend operation until IPA is no longer used by AP.
6283*/
6284int ipa3_ap_suspend(struct device *dev)
6285{
6286 int i;
6287
6288 IPADBG("Enter...\n");
6289
6290 /* In case there is a tx/rx handler in polling mode fail to suspend */
6291 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
6292 if (ipa3_ctx->ep[i].sys &&
6293 atomic_read(&ipa3_ctx->ep[i].sys->curr_polling_state)) {
6294 IPAERR("EP %d is in polling state, do not suspend\n",
6295 i);
6296 return -EAGAIN;
6297 }
6298 }
6299
Michael Adisumarta3e350812017-09-18 14:54:36 -07006300 if (ipa3_ctx->use_ipa_pm) {
6301 ipa_pm_deactivate_all_deferred();
6302 } else {
6303 /*
6304 * Release transport IPA resource without waiting
6305 * for inactivity timer
6306 */
6307 atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
6308 ipa3_transport_release_resource(NULL);
6309 }
Amir Levy9659e592016-10-27 18:08:27 +03006310 IPADBG("Exit\n");
6311
6312 return 0;
6313}
6314
6315/**
6316* ipa3_ap_resume() - resume callback for runtime_pm
6317* @dev: pointer to device
6318*
6319* This callback will be invoked by the runtime_pm framework when an AP resume
6320* operation is invoked.
6321*
6322* Always returns 0 since resume should always succeed.
6323*/
6324int ipa3_ap_resume(struct device *dev)
6325{
6326 return 0;
6327}
6328
6329struct ipa3_context *ipa3_get_ctx(void)
6330{
6331 return ipa3_ctx;
6332}
6333
Amir Levy9659e592016-10-27 18:08:27 +03006334static void ipa_gsi_notify_cb(struct gsi_per_notify *notify)
6335{
6336 switch (notify->evt_id) {
6337 case GSI_PER_EVT_GLOB_ERROR:
6338 IPAERR("Got GSI_PER_EVT_GLOB_ERROR\n");
6339 IPAERR("Err_desc = 0x%04x\n", notify->data.err_desc);
6340 break;
6341 case GSI_PER_EVT_GLOB_GP1:
6342 IPAERR("Got GSI_PER_EVT_GLOB_GP1\n");
6343 BUG();
6344 break;
6345 case GSI_PER_EVT_GLOB_GP2:
6346 IPAERR("Got GSI_PER_EVT_GLOB_GP2\n");
6347 BUG();
6348 break;
6349 case GSI_PER_EVT_GLOB_GP3:
6350 IPAERR("Got GSI_PER_EVT_GLOB_GP3\n");
6351 BUG();
6352 break;
6353 case GSI_PER_EVT_GENERAL_BREAK_POINT:
6354 IPAERR("Got GSI_PER_EVT_GENERAL_BREAK_POINT\n");
6355 break;
6356 case GSI_PER_EVT_GENERAL_BUS_ERROR:
6357 IPAERR("Got GSI_PER_EVT_GENERAL_BUS_ERROR\n");
6358 BUG();
6359 break;
6360 case GSI_PER_EVT_GENERAL_CMD_FIFO_OVERFLOW:
6361 IPAERR("Got GSI_PER_EVT_GENERAL_CMD_FIFO_OVERFLOW\n");
6362 BUG();
6363 break;
6364 case GSI_PER_EVT_GENERAL_MCS_STACK_OVERFLOW:
6365 IPAERR("Got GSI_PER_EVT_GENERAL_MCS_STACK_OVERFLOW\n");
6366 BUG();
6367 break;
6368 default:
6369 IPAERR("Received unexpected evt: %d\n",
6370 notify->evt_id);
6371 BUG();
6372 }
6373}
6374
6375int ipa3_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data)
6376{
6377 struct ipa3_ready_cb_info *cb_info = NULL;
6378
6379 /* check ipa3_ctx existed or not */
6380 if (!ipa3_ctx) {
6381 IPADBG("IPA driver haven't initialized\n");
6382 return -ENXIO;
6383 }
6384 mutex_lock(&ipa3_ctx->lock);
6385 if (ipa3_ctx->ipa_initialization_complete) {
6386 mutex_unlock(&ipa3_ctx->lock);
6387 IPADBG("IPA driver finished initialization already\n");
6388 return -EEXIST;
6389 }
6390
6391 cb_info = kmalloc(sizeof(struct ipa3_ready_cb_info), GFP_KERNEL);
6392 if (!cb_info) {
6393 mutex_unlock(&ipa3_ctx->lock);
6394 return -ENOMEM;
6395 }
6396
6397 cb_info->ready_cb = ipa_ready_cb;
6398 cb_info->user_data = user_data;
6399
6400 list_add_tail(&cb_info->link, &ipa3_ctx->ipa_ready_cb_list);
6401 mutex_unlock(&ipa3_ctx->lock);
6402
6403 return 0;
6404}
6405
6406int ipa3_iommu_map(struct iommu_domain *domain,
6407 unsigned long iova, phys_addr_t paddr, size_t size, int prot)
6408{
6409 struct ipa_smmu_cb_ctx *ap_cb = ipa3_get_smmu_ctx();
6410 struct ipa_smmu_cb_ctx *uc_cb = ipa3_get_uc_smmu_ctx();
6411
6412 IPADBG("domain =0x%p iova 0x%lx\n", domain, iova);
6413 IPADBG("paddr =0x%pa size 0x%x\n", &paddr, (u32)size);
6414
6415 /* make sure no overlapping */
6416 if (domain == ipa3_get_smmu_domain()) {
6417 if (iova >= ap_cb->va_start && iova < ap_cb->va_end) {
6418 IPAERR("iommu AP overlap addr 0x%lx\n", iova);
6419 ipa_assert();
6420 return -EFAULT;
6421 }
6422 } else if (domain == ipa3_get_wlan_smmu_domain()) {
6423 /* wlan is one time map */
6424 } else if (domain == ipa3_get_uc_smmu_domain()) {
6425 if (iova >= uc_cb->va_start && iova < uc_cb->va_end) {
6426 IPAERR("iommu uC overlap addr 0x%lx\n", iova);
6427 ipa_assert();
6428 return -EFAULT;
6429 }
6430 } else {
6431 IPAERR("Unexpected domain 0x%p\n", domain);
6432 ipa_assert();
6433 return -EFAULT;
6434 }
6435
6436 return iommu_map(domain, iova, paddr, size, prot);
6437}
6438
Michael Adisumartad04e6d62017-11-09 17:46:35 -08006439/**
6440 * ipa3_get_smmu_params()- Return the ipa3 smmu related params.
6441 */
6442int ipa3_get_smmu_params(struct ipa_smmu_in_params *in,
6443 struct ipa_smmu_out_params *out)
6444{
6445 bool is_smmu_enable = 0;
6446
6447 if (out == NULL || in == NULL) {
6448 IPAERR("bad parms for Client SMMU out params\n");
6449 return -EINVAL;
6450 }
6451
6452 if (!ipa3_ctx) {
6453 IPAERR("IPA not yet initialized\n");
6454 return -EINVAL;
6455 }
6456
6457 switch (in->smmu_client) {
6458 case IPA_SMMU_WLAN_CLIENT:
6459 is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] |
6460 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN]);
6461 break;
6462 default:
6463 is_smmu_enable = 0;
6464 IPAERR("Trying to get illegal clients SMMU status");
6465 return -EINVAL;
6466 }
6467
6468 out->smmu_enable = is_smmu_enable;
6469
6470 return 0;
6471}
6472
Amir Levy9659e592016-10-27 18:08:27 +03006473MODULE_LICENSE("GPL v2");
6474MODULE_DESCRIPTION("IPA HW device driver");