blob: 716ec793d32a22b1d02375dc809b45abbbeac207 [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
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08003858 if (!ipa3_ctx->enable_clock_scaling)
3859 return 0;
3860
Michael Adisumartac06df412017-09-19 10:10:35 -07003861 IPADBG_LOW("idx = %d\n", idx);
3862
3863 if (idx <= 0 || idx >= ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases) {
3864 IPAERR("bad voltage\n");
3865 return -EINVAL;
3866 }
3867
3868 if (idx == 1)
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08003869 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs2;
Michael Adisumartac06df412017-09-19 10:10:35 -07003870 else if (idx == 2)
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08003871 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
Michael Adisumartac06df412017-09-19 10:10:35 -07003872 else if (idx == 3)
Michael Adisumartafd2d2fc92017-12-11 11:34:02 -08003873 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
3874 else if (idx == 4)
Michael Adisumartac06df412017-09-19 10:10:35 -07003875 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
3876 else {
3877 IPAERR("bad voltage\n");
3878 WARN_ON(1);
3879 return -EFAULT;
3880 }
3881
3882 if (clk_rate == ipa3_ctx->curr_ipa_clk_rate) {
3883 IPADBG_LOW("Same voltage\n");
3884 return 0;
3885 }
3886
3887 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
3888 ipa3_ctx->curr_ipa_clk_rate = clk_rate;
3889 ipa3_ctx->ipa3_active_clients.bus_vote_idx = idx;
3890 IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
3891 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) > 0) {
3892 if (ipa3_clk)
3893 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
3894 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
3895 ipa3_get_bus_vote()))
3896 WARN_ON(1);
3897 } else {
3898 IPADBG_LOW("clocks are gated, not setting rate\n");
3899 }
3900 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
3901 IPADBG_LOW("Done\n");
3902
3903 return 0;
3904}
3905
Amir Levy9659e592016-10-27 18:08:27 +03003906int ipa3_set_required_perf_profile(enum ipa_voltage_level floor_voltage,
3907 u32 bandwidth_mbps)
3908{
3909 enum ipa_voltage_level needed_voltage;
3910 u32 clk_rate;
3911
3912 IPADBG_LOW("floor_voltage=%d, bandwidth_mbps=%u",
3913 floor_voltage, bandwidth_mbps);
3914
3915 if (floor_voltage < IPA_VOLTAGE_UNSPECIFIED ||
3916 floor_voltage >= IPA_VOLTAGE_MAX) {
3917 IPAERR("bad voltage\n");
3918 return -EINVAL;
3919 }
3920
3921 if (ipa3_ctx->enable_clock_scaling) {
3922 IPADBG_LOW("Clock scaling is enabled\n");
3923 if (bandwidth_mbps >=
3924 ipa3_ctx->ctrl->clock_scaling_bw_threshold_turbo)
3925 needed_voltage = IPA_VOLTAGE_TURBO;
3926 else if (bandwidth_mbps >=
3927 ipa3_ctx->ctrl->clock_scaling_bw_threshold_nominal)
3928 needed_voltage = IPA_VOLTAGE_NOMINAL;
Skylar Chang448d8b82017-08-08 17:30:32 -07003929 else if (bandwidth_mbps >=
3930 ipa3_ctx->ctrl->clock_scaling_bw_threshold_svs)
Amir Levy9659e592016-10-27 18:08:27 +03003931 needed_voltage = IPA_VOLTAGE_SVS;
Skylar Chang448d8b82017-08-08 17:30:32 -07003932 else
3933 needed_voltage = IPA_VOLTAGE_SVS2;
Amir Levy9659e592016-10-27 18:08:27 +03003934 } else {
3935 IPADBG_LOW("Clock scaling is disabled\n");
3936 needed_voltage = IPA_VOLTAGE_NOMINAL;
3937 }
3938
3939 needed_voltage = max(needed_voltage, floor_voltage);
3940 switch (needed_voltage) {
Skylar Chang448d8b82017-08-08 17:30:32 -07003941 case IPA_VOLTAGE_SVS2:
3942 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs2;
3943 break;
Amir Levy9659e592016-10-27 18:08:27 +03003944 case IPA_VOLTAGE_SVS:
3945 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
3946 break;
3947 case IPA_VOLTAGE_NOMINAL:
3948 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
3949 break;
3950 case IPA_VOLTAGE_TURBO:
3951 clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
3952 break;
3953 default:
3954 IPAERR("bad voltage\n");
3955 WARN_ON(1);
3956 return -EFAULT;
3957 }
3958
3959 if (clk_rate == ipa3_ctx->curr_ipa_clk_rate) {
3960 IPADBG_LOW("Same voltage\n");
3961 return 0;
3962 }
3963
Skylar Chang242952b2017-07-20 15:04:05 -07003964 /* Hold the mutex to avoid race conditions with ipa3_enable_clocks() */
3965 mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03003966 ipa3_ctx->curr_ipa_clk_rate = clk_rate;
3967 IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
Skylar Chang242952b2017-07-20 15:04:05 -07003968 if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) > 0) {
Ghanim Fodi6a831342017-03-07 18:19:15 +02003969 if (ipa3_clk)
3970 clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
3971 if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
Skylar Chang242952b2017-07-20 15:04:05 -07003972 ipa3_get_bus_vote()))
Ghanim Fodi6a831342017-03-07 18:19:15 +02003973 WARN_ON(1);
Amir Levy9659e592016-10-27 18:08:27 +03003974 } else {
3975 IPADBG_LOW("clocks are gated, not setting rate\n");
3976 }
Skylar Chang242952b2017-07-20 15:04:05 -07003977 mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03003978 IPADBG_LOW("Done\n");
Skylar Chang1cbe99c2017-05-01 13:44:03 -07003979
Amir Levy9659e592016-10-27 18:08:27 +03003980 return 0;
3981}
3982
Amir Levya59ed3f2017-03-05 17:30:55 +02003983static void ipa3_process_irq_schedule_rel(void)
Amir Levy9659e592016-10-27 18:08:27 +03003984{
3985 queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
Amir Levya59ed3f2017-03-05 17:30:55 +02003986 &ipa3_transport_release_resource_work,
Amir Levy9659e592016-10-27 18:08:27 +03003987 msecs_to_jiffies(IPA_TRANSPORT_PROD_TIMEOUT_MSEC));
3988}
3989
3990/**
3991* ipa3_suspend_handler() - Handles the suspend interrupt:
3992* wakes up the suspended peripheral by requesting its consumer
3993* @interrupt: Interrupt type
3994* @private_data: The client's private data
3995* @interrupt_data: Interrupt specific information data
3996*/
3997void ipa3_suspend_handler(enum ipa_irq_type interrupt,
3998 void *private_data,
3999 void *interrupt_data)
4000{
4001 enum ipa_rm_resource_name resource;
4002 u32 suspend_data =
4003 ((struct ipa_tx_suspend_irq_data *)interrupt_data)->endpoints;
4004 u32 bmsk = 1;
4005 u32 i = 0;
4006 int res;
4007 struct ipa_ep_cfg_holb holb_cfg;
Michael Adisumarta3e350812017-09-18 14:54:36 -07004008 u32 pipe_bitmask = 0;
Amir Levy9659e592016-10-27 18:08:27 +03004009
4010 IPADBG("interrupt=%d, interrupt_data=%u\n",
4011 interrupt, suspend_data);
4012 memset(&holb_cfg, 0, sizeof(holb_cfg));
4013 holb_cfg.tmr_val = 0;
4014
Michael Adisumarta3e350812017-09-18 14:54:36 -07004015 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++, bmsk = bmsk << 1) {
Amir Levy9659e592016-10-27 18:08:27 +03004016 if ((suspend_data & bmsk) && (ipa3_ctx->ep[i].valid)) {
Michael Adisumarta3e350812017-09-18 14:54:36 -07004017 if (ipa3_ctx->use_ipa_pm) {
4018 pipe_bitmask |= bmsk;
4019 continue;
4020 }
Amir Levy9659e592016-10-27 18:08:27 +03004021 if (IPA_CLIENT_IS_APPS_CONS(ipa3_ctx->ep[i].client)) {
4022 /*
4023 * pipe will be unsuspended as part of
4024 * enabling IPA clocks
4025 */
Skylar Chang0d06bb12017-02-24 11:22:03 -08004026 mutex_lock(&ipa3_ctx->transport_pm.
4027 transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004028 if (!atomic_read(
4029 &ipa3_ctx->transport_pm.dec_clients)
4030 ) {
4031 IPA_ACTIVE_CLIENTS_INC_EP(
4032 ipa3_ctx->ep[i].client);
4033 IPADBG_LOW("Pipes un-suspended.\n");
4034 IPADBG_LOW("Enter poll mode.\n");
4035 atomic_set(
4036 &ipa3_ctx->transport_pm.dec_clients,
4037 1);
Skylar Chang9e3b6492017-11-07 09:49:48 -08004038 /*
4039 * acquire wake lock as long as suspend
4040 * vote is held
4041 */
4042 ipa3_inc_acquire_wakelock();
Amir Levya59ed3f2017-03-05 17:30:55 +02004043 ipa3_process_irq_schedule_rel();
Amir Levy9659e592016-10-27 18:08:27 +03004044 }
Skylar Chang0d06bb12017-02-24 11:22:03 -08004045 mutex_unlock(&ipa3_ctx->transport_pm.
4046 transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004047 } else {
4048 resource = ipa3_get_rm_resource_from_ep(i);
4049 res =
4050 ipa_rm_request_resource_with_timer(resource);
4051 if (res == -EPERM &&
4052 IPA_CLIENT_IS_CONS(
4053 ipa3_ctx->ep[i].client)) {
4054 holb_cfg.en = 1;
4055 res = ipa3_cfg_ep_holb_by_client(
4056 ipa3_ctx->ep[i].client, &holb_cfg);
4057 if (res) {
4058 IPAERR("holb en fail, stall\n");
4059 BUG();
4060 }
4061 }
4062 }
4063 }
Michael Adisumarta3e350812017-09-18 14:54:36 -07004064 }
4065 if (ipa3_ctx->use_ipa_pm) {
4066 res = ipa_pm_handle_suspend(pipe_bitmask);
4067 if (res) {
4068 IPAERR("ipa_pm_handle_suspend failed %d\n", res);
4069 return;
4070 }
Amir Levy9659e592016-10-27 18:08:27 +03004071 }
4072}
4073
4074/**
4075* ipa3_restore_suspend_handler() - restores the original suspend IRQ handler
4076* as it was registered in the IPA init sequence.
4077* Return codes:
4078* 0: success
4079* -EPERM: failed to remove current handler or failed to add original handler
4080*/
4081int ipa3_restore_suspend_handler(void)
4082{
4083 int result = 0;
4084
4085 result = ipa3_remove_interrupt_handler(IPA_TX_SUSPEND_IRQ);
4086 if (result) {
4087 IPAERR("remove handler for suspend interrupt failed\n");
4088 return -EPERM;
4089 }
4090
4091 result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
4092 ipa3_suspend_handler, false, NULL);
4093 if (result) {
4094 IPAERR("register handler for suspend interrupt failed\n");
4095 result = -EPERM;
4096 }
4097
4098 IPADBG("suspend handler successfully restored\n");
4099
4100 return result;
4101}
4102
4103static int ipa3_apps_cons_release_resource(void)
4104{
4105 return 0;
4106}
4107
4108static int ipa3_apps_cons_request_resource(void)
4109{
4110 return 0;
4111}
4112
Amir Levya59ed3f2017-03-05 17:30:55 +02004113static void ipa3_transport_release_resource(struct work_struct *work)
Amir Levy9659e592016-10-27 18:08:27 +03004114{
Sridhar Ancha99b505b2016-04-21 23:11:10 +05304115 mutex_lock(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004116 /* check whether still need to decrease client usage */
4117 if (atomic_read(&ipa3_ctx->transport_pm.dec_clients)) {
4118 if (atomic_read(&ipa3_ctx->transport_pm.eot_activity)) {
4119 IPADBG("EOT pending Re-scheduling\n");
Amir Levya59ed3f2017-03-05 17:30:55 +02004120 ipa3_process_irq_schedule_rel();
Amir Levy9659e592016-10-27 18:08:27 +03004121 } else {
4122 atomic_set(&ipa3_ctx->transport_pm.dec_clients, 0);
Skylar Chang9e3b6492017-11-07 09:49:48 -08004123 ipa3_dec_release_wakelock();
Amir Levya59ed3f2017-03-05 17:30:55 +02004124 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("TRANSPORT_RESOURCE");
Amir Levy9659e592016-10-27 18:08:27 +03004125 }
4126 }
4127 atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
Sridhar Ancha99b505b2016-04-21 23:11:10 +05304128 mutex_unlock(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03004129}
4130
4131int ipa3_create_apps_resource(void)
4132{
4133 struct ipa_rm_create_params apps_cons_create_params;
4134 struct ipa_rm_perf_profile profile;
4135 int result = 0;
4136
4137 memset(&apps_cons_create_params, 0,
4138 sizeof(apps_cons_create_params));
4139 apps_cons_create_params.name = IPA_RM_RESOURCE_APPS_CONS;
4140 apps_cons_create_params.request_resource =
4141 ipa3_apps_cons_request_resource;
4142 apps_cons_create_params.release_resource =
4143 ipa3_apps_cons_release_resource;
4144 result = ipa_rm_create_resource(&apps_cons_create_params);
4145 if (result) {
4146 IPAERR("ipa_rm_create_resource failed\n");
4147 return result;
4148 }
4149
4150 profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
4151 ipa_rm_set_perf_profile(IPA_RM_RESOURCE_APPS_CONS, &profile);
4152
4153 return result;
4154}
4155
4156/**
4157 * ipa3_init_interrupts() - Register to IPA IRQs
4158 *
4159 * Return codes: 0 in success, negative in failure
4160 *
4161 */
4162int ipa3_init_interrupts(void)
4163{
4164 int result;
4165
4166 /*register IPA IRQ handler*/
4167 result = ipa3_interrupts_init(ipa3_res.ipa_irq, 0,
4168 master_dev);
4169 if (result) {
4170 IPAERR("ipa interrupts initialization failed\n");
4171 return -ENODEV;
4172 }
4173
4174 /*add handler for suspend interrupt*/
4175 result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
4176 ipa3_suspend_handler, false, NULL);
4177 if (result) {
4178 IPAERR("register handler for suspend interrupt failed\n");
4179 result = -ENODEV;
4180 goto fail_add_interrupt_handler;
4181 }
4182
4183 return 0;
4184
4185fail_add_interrupt_handler:
4186 free_irq(ipa3_res.ipa_irq, master_dev);
4187 return result;
4188}
4189
4190/**
4191 * ipa3_destroy_flt_tbl_idrs() - destroy the idr structure for flt tables
4192 * The idr strcuture per filtering table is intended for rule id generation
4193 * per filtering rule.
4194 */
4195static void ipa3_destroy_flt_tbl_idrs(void)
4196{
4197 int i;
4198 struct ipa3_flt_tbl *flt_tbl;
4199
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004200 idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
4201 idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
4202
Amir Levy9659e592016-10-27 18:08:27 +03004203 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4204 if (!ipa_is_ep_support_flt(i))
4205 continue;
4206
4207 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004208 flt_tbl->rule_ids = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004209 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004210 flt_tbl->rule_ids = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004211 }
4212}
4213
4214static void ipa3_freeze_clock_vote_and_notify_modem(void)
4215{
4216 int res;
Amir Levy9659e592016-10-27 18:08:27 +03004217 struct ipa_active_client_logging_info log_info;
4218
4219 if (ipa3_ctx->smp2p_info.res_sent)
4220 return;
4221
Skylar Change1209942017-02-02 14:26:38 -08004222 if (ipa3_ctx->smp2p_info.out_base_id == 0) {
4223 IPAERR("smp2p out gpio not assigned\n");
4224 return;
4225 }
4226
Amir Levy9659e592016-10-27 18:08:27 +03004227 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "FREEZE_VOTE");
4228 res = ipa3_inc_client_enable_clks_no_block(&log_info);
4229 if (res)
Skylar Change1209942017-02-02 14:26:38 -08004230 ipa3_ctx->smp2p_info.ipa_clk_on = false;
Amir Levy9659e592016-10-27 18:08:27 +03004231 else
Skylar Change1209942017-02-02 14:26:38 -08004232 ipa3_ctx->smp2p_info.ipa_clk_on = true;
Amir Levy9659e592016-10-27 18:08:27 +03004233
Skylar Change1209942017-02-02 14:26:38 -08004234 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4235 IPA_GPIO_OUT_CLK_VOTE_IDX,
4236 ipa3_ctx->smp2p_info.ipa_clk_on);
4237 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4238 IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 1);
Amir Levy9659e592016-10-27 18:08:27 +03004239
Skylar Change1209942017-02-02 14:26:38 -08004240 ipa3_ctx->smp2p_info.res_sent = true;
4241 IPADBG("IPA clocks are %s\n",
4242 ipa3_ctx->smp2p_info.ipa_clk_on ? "ON" : "OFF");
4243}
4244
4245void ipa3_reset_freeze_vote(void)
4246{
4247 if (ipa3_ctx->smp2p_info.res_sent == false)
4248 return;
4249
4250 if (ipa3_ctx->smp2p_info.ipa_clk_on)
4251 IPA_ACTIVE_CLIENTS_DEC_SPECIAL("FREEZE_VOTE");
4252
4253 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4254 IPA_GPIO_OUT_CLK_VOTE_IDX, 0);
4255 gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
4256 IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 0);
4257
4258 ipa3_ctx->smp2p_info.res_sent = false;
4259 ipa3_ctx->smp2p_info.ipa_clk_on = false;
Amir Levy9659e592016-10-27 18:08:27 +03004260}
4261
4262static int ipa3_panic_notifier(struct notifier_block *this,
4263 unsigned long event, void *ptr)
4264{
4265 int res;
4266
4267 ipa3_freeze_clock_vote_and_notify_modem();
4268
4269 IPADBG("Calling uC panic handler\n");
4270 res = ipa3_uc_panic_notifier(this, event, ptr);
4271 if (res)
4272 IPAERR("uC panic handler failed %d\n", res);
4273
4274 return NOTIFY_DONE;
4275}
4276
4277static struct notifier_block ipa3_panic_blk = {
4278 .notifier_call = ipa3_panic_notifier,
4279 /* IPA panic handler needs to run before modem shuts down */
4280 .priority = INT_MAX,
4281};
4282
4283static void ipa3_register_panic_hdlr(void)
4284{
4285 atomic_notifier_chain_register(&panic_notifier_list,
4286 &ipa3_panic_blk);
4287}
4288
4289static void ipa3_trigger_ipa_ready_cbs(void)
4290{
4291 struct ipa3_ready_cb_info *info;
4292
4293 mutex_lock(&ipa3_ctx->lock);
4294
4295 /* Call all the CBs */
4296 list_for_each_entry(info, &ipa3_ctx->ipa_ready_cb_list, link)
4297 if (info->ready_cb)
4298 info->ready_cb(info->user_data);
4299
4300 mutex_unlock(&ipa3_ctx->lock);
4301}
4302
4303static int ipa3_gsi_pre_fw_load_init(void)
4304{
4305 int result;
4306
4307 result = gsi_configure_regs(ipa3_res.transport_mem_base,
4308 ipa3_res.transport_mem_size,
4309 ipa3_res.ipa_mem_base);
4310 if (result) {
4311 IPAERR("Failed to configure GSI registers\n");
4312 return -EINVAL;
4313 }
4314
4315 return 0;
4316}
4317
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004318static void ipa3_uc_is_loaded(void)
4319{
4320 IPADBG("\n");
4321 complete_all(&ipa3_ctx->uc_loaded_completion_obj);
4322}
4323
Amir Levy41644242016-11-03 15:38:09 +02004324static enum gsi_ver ipa3_get_gsi_ver(enum ipa_hw_type ipa_hw_type)
4325{
4326 enum gsi_ver gsi_ver;
4327
4328 switch (ipa_hw_type) {
4329 case IPA_HW_v3_0:
4330 case IPA_HW_v3_1:
4331 gsi_ver = GSI_VER_1_0;
4332 break;
4333 case IPA_HW_v3_5:
4334 gsi_ver = GSI_VER_1_2;
4335 break;
4336 case IPA_HW_v3_5_1:
4337 gsi_ver = GSI_VER_1_3;
4338 break;
Michael Adisumarta891a4ff2017-05-16 16:40:06 -07004339 case IPA_HW_v4_0:
4340 gsi_ver = GSI_VER_2_0;
4341 break;
Amir Levy41644242016-11-03 15:38:09 +02004342 default:
4343 IPAERR("No GSI version for ipa type %d\n", ipa_hw_type);
4344 WARN_ON(1);
4345 gsi_ver = GSI_VER_ERR;
4346 }
4347
4348 IPADBG("GSI version %d\n", gsi_ver);
4349
4350 return gsi_ver;
4351}
4352
Amir Levy9659e592016-10-27 18:08:27 +03004353/**
4354 * ipa3_post_init() - Initialize the IPA Driver (Part II).
4355 * This part contains all initialization which requires interaction with
Amir Levya59ed3f2017-03-05 17:30:55 +02004356 * IPA HW (via GSI).
Amir Levy9659e592016-10-27 18:08:27 +03004357 *
4358 * @resource_p: contain platform specific values from DST file
4359 * @pdev: The platform device structure representing the IPA driver
4360 *
4361 * Function initialization process:
Amir Levy54fe4d32017-03-16 11:21:49 +02004362 * - Initialize endpoints bitmaps
4363 * - Initialize resource groups min and max values
4364 * - Initialize filtering lists heads and idr
4365 * - Initialize interrupts
Amir Levya59ed3f2017-03-05 17:30:55 +02004366 * - Register GSI
Amir Levy9659e592016-10-27 18:08:27 +03004367 * - Setup APPS pipes
4368 * - Initialize tethering bridge
4369 * - Initialize IPA debugfs
4370 * - Initialize IPA uC interface
4371 * - Initialize WDI interface
4372 * - Initialize USB interface
4373 * - Register for panic handler
4374 * - Trigger IPA ready callbacks (to all subscribers)
4375 * - Trigger IPA completion object (to all who wait on it)
4376 */
4377static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p,
4378 struct device *ipa_dev)
4379{
4380 int result;
Amir Levy9659e592016-10-27 18:08:27 +03004381 struct gsi_per_props gsi_props;
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004382 struct ipa3_uc_hdlrs uc_hdlrs = { 0 };
Amir Levy54fe4d32017-03-16 11:21:49 +02004383 struct ipa3_flt_tbl *flt_tbl;
4384 int i;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004385 struct idr *idr;
Amir Levy54fe4d32017-03-16 11:21:49 +02004386
Utkarsh Saxenaded78142017-05-03 14:04:30 +05304387 if (ipa3_ctx == NULL) {
4388 IPADBG("IPA driver haven't initialized\n");
4389 return -ENXIO;
4390 }
4391
4392 /* Prevent consequent calls from trying to load the FW again. */
4393 if (ipa3_ctx->ipa_initialization_complete)
4394 return 0;
4395
Amir Levy54fe4d32017-03-16 11:21:49 +02004396 /*
4397 * indication whether working in MHI config or non MHI config is given
4398 * in ipa3_write which is launched before ipa3_post_init. i.e. from
4399 * this point it is safe to use ipa3_ep_mapping array and the correct
4400 * entry will be returned from ipa3_get_hw_type_index()
4401 */
4402 ipa_init_ep_flt_bitmap();
4403 IPADBG("EP with flt support bitmap 0x%x (%u pipes)\n",
4404 ipa3_ctx->ep_flt_bitmap, ipa3_ctx->ep_flt_num);
4405
4406 /* Assign resource limitation to each group */
4407 ipa3_set_resorce_groups_min_max_limits();
4408
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004409 idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
4410 idr_init(idr);
4411 idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
4412 idr_init(idr);
4413
Amir Levy54fe4d32017-03-16 11:21:49 +02004414 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4415 if (!ipa_is_ep_support_flt(i))
4416 continue;
4417
4418 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
4419 INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
4420 flt_tbl->in_sys[IPA_RULE_HASHABLE] =
4421 !ipa3_ctx->ip4_flt_tbl_hash_lcl;
4422 flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
4423 !ipa3_ctx->ip4_flt_tbl_nhash_lcl;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004424 flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v4];
Amir Levy54fe4d32017-03-16 11:21:49 +02004425
4426 flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
4427 INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
4428 flt_tbl->in_sys[IPA_RULE_HASHABLE] =
4429 !ipa3_ctx->ip6_flt_tbl_hash_lcl;
4430 flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
4431 !ipa3_ctx->ip6_flt_tbl_nhash_lcl;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07004432 flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v6];
Amir Levy54fe4d32017-03-16 11:21:49 +02004433 }
4434
4435 if (!ipa3_ctx->apply_rg10_wa) {
4436 result = ipa3_init_interrupts();
4437 if (result) {
4438 IPAERR("ipa initialization of interrupts failed\n");
4439 result = -ENODEV;
4440 goto fail_register_device;
4441 }
4442 } else {
4443 IPADBG("Initialization of ipa interrupts skipped\n");
4444 }
Amir Levy9659e592016-10-27 18:08:27 +03004445
Amir Levy3afd94a2017-01-05 10:19:13 +02004446 /*
Amir Levy5cfbb322017-01-09 14:53:02 +02004447 * IPAv3.5 and above requires to disable prefetch for USB in order
4448 * to allow MBIM to work, currently MBIM is not needed in MHI mode.
Amir Levy3afd94a2017-01-05 10:19:13 +02004449 */
Michael Adisumartad68ab112017-06-14 11:40:06 -07004450 if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5
4451 && ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) &&
Amir Levy5cfbb322017-01-09 14:53:02 +02004452 (!ipa3_ctx->ipa_config_is_mhi))
Amir Levy3afd94a2017-01-05 10:19:13 +02004453 ipa3_disable_prefetch(IPA_CLIENT_USB_CONS);
4454
Amir Levya59ed3f2017-03-05 17:30:55 +02004455 memset(&gsi_props, 0, sizeof(gsi_props));
4456 gsi_props.ver = ipa3_get_gsi_ver(resource_p->ipa_hw_type);
4457 gsi_props.ee = resource_p->ee;
4458 gsi_props.intr = GSI_INTR_IRQ;
4459 gsi_props.irq = resource_p->transport_irq;
4460 gsi_props.phys_addr = resource_p->transport_mem_base;
4461 gsi_props.size = resource_p->transport_mem_size;
4462 gsi_props.notify_cb = ipa_gsi_notify_cb;
4463 gsi_props.req_clk_cb = NULL;
4464 gsi_props.rel_clk_cb = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03004465
Ghanim Fodic823bc62017-10-21 17:29:53 +03004466 if (ipa3_ctx->ipa_config_is_mhi) {
4467 gsi_props.mhi_er_id_limits_valid = true;
4468 gsi_props.mhi_er_id_limits[0] = resource_p->mhi_evid_limits[0];
4469 gsi_props.mhi_er_id_limits[1] = resource_p->mhi_evid_limits[1];
4470 }
4471
Amir Levya59ed3f2017-03-05 17:30:55 +02004472 result = gsi_register_device(&gsi_props,
4473 &ipa3_ctx->gsi_dev_hdl);
4474 if (result != GSI_STATUS_SUCCESS) {
4475 IPAERR(":gsi register error - %d\n", result);
4476 result = -ENODEV;
4477 goto fail_register_device;
Amir Levy9659e592016-10-27 18:08:27 +03004478 }
Amir Levya59ed3f2017-03-05 17:30:55 +02004479 IPADBG("IPA gsi is registered\n");
Amir Levy9659e592016-10-27 18:08:27 +03004480
4481 /* setup the AP-IPA pipes */
4482 if (ipa3_setup_apps_pipes()) {
4483 IPAERR(":failed to setup IPA-Apps pipes\n");
4484 result = -ENODEV;
4485 goto fail_setup_apps_pipes;
4486 }
Amir Levya59ed3f2017-03-05 17:30:55 +02004487 IPADBG("IPA GPI pipes were connected\n");
Amir Levy9659e592016-10-27 18:08:27 +03004488
4489 if (ipa3_ctx->use_ipa_teth_bridge) {
4490 /* Initialize the tethering bridge driver */
4491 result = ipa3_teth_bridge_driver_init();
4492 if (result) {
4493 IPAERR(":teth_bridge init failed (%d)\n", -result);
4494 result = -ENODEV;
4495 goto fail_teth_bridge_driver_init;
4496 }
4497 IPADBG("teth_bridge initialized");
4498 }
4499
4500 ipa3_debugfs_init();
4501
4502 result = ipa3_uc_interface_init();
4503 if (result)
4504 IPAERR(":ipa Uc interface init failed (%d)\n", -result);
4505 else
4506 IPADBG(":ipa Uc interface init ok\n");
4507
Skylar Chang0c17c7d2016-10-31 09:57:54 -07004508 uc_hdlrs.ipa_uc_loaded_hdlr = ipa3_uc_is_loaded;
4509 ipa3_uc_register_handlers(IPA_HW_FEATURE_COMMON, &uc_hdlrs);
4510
Amir Levy9659e592016-10-27 18:08:27 +03004511 result = ipa3_wdi_init();
4512 if (result)
4513 IPAERR(":wdi init failed (%d)\n", -result);
4514 else
4515 IPADBG(":wdi init ok\n");
4516
4517 result = ipa3_ntn_init();
4518 if (result)
4519 IPAERR(":ntn init failed (%d)\n", -result);
4520 else
4521 IPADBG(":ntn init ok\n");
4522
Skylar Chang6f6e3072017-07-28 10:03:47 -07004523 result = ipa_hw_stats_init();
4524 if (result)
4525 IPAERR("fail to init stats %d\n", result);
4526 else
4527 IPADBG(":stats init ok\n");
4528
Amir Levy9659e592016-10-27 18:08:27 +03004529 ipa3_register_panic_hdlr();
4530
4531 ipa3_ctx->q6_proxy_clk_vote_valid = true;
Mohammed Javid05b05d02017-11-13 23:43:27 +05304532 ipa3_ctx->q6_proxy_clk_vote_cnt++;
Amir Levy9659e592016-10-27 18:08:27 +03004533
4534 mutex_lock(&ipa3_ctx->lock);
4535 ipa3_ctx->ipa_initialization_complete = true;
4536 mutex_unlock(&ipa3_ctx->lock);
4537
4538 ipa3_trigger_ipa_ready_cbs();
4539 complete_all(&ipa3_ctx->init_completion_obj);
4540 pr_info("IPA driver initialization was successful.\n");
4541
4542 return 0;
4543
4544fail_teth_bridge_driver_init:
4545 ipa3_teardown_apps_pipes();
4546fail_setup_apps_pipes:
Amir Levya59ed3f2017-03-05 17:30:55 +02004547 gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
Amir Levy9659e592016-10-27 18:08:27 +03004548fail_register_device:
Amir Levy9659e592016-10-27 18:08:27 +03004549 ipa3_destroy_flt_tbl_idrs();
Amir Levy9659e592016-10-27 18:08:27 +03004550 return result;
4551}
4552
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004553static int ipa3_manual_load_ipa_fws(void)
Amir Levy9659e592016-10-27 18:08:27 +03004554{
4555 int result;
4556 const struct firmware *fw;
4557
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004558 IPADBG("Manual FW loading process initiated\n");
Amir Levy9659e592016-10-27 18:08:27 +03004559
4560 result = request_firmware(&fw, IPA_FWS_PATH, ipa3_ctx->dev);
4561 if (result < 0) {
4562 IPAERR("request_firmware failed, error %d\n", result);
4563 return result;
4564 }
4565 if (fw == NULL) {
4566 IPAERR("Firmware is NULL!\n");
4567 return -EINVAL;
4568 }
4569
4570 IPADBG("FWs are available for loading\n");
4571
Ghanim Fodi37b64952017-01-24 15:42:30 +02004572 result = ipa3_load_fws(fw, ipa3_res.transport_mem_base);
Amir Levy9659e592016-10-27 18:08:27 +03004573 if (result) {
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004574 IPAERR("Manual IPA FWs loading has failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03004575 release_firmware(fw);
4576 return result;
4577 }
4578
4579 result = gsi_enable_fw(ipa3_res.transport_mem_base,
Amir Levy85dcd172016-12-06 17:47:39 +02004580 ipa3_res.transport_mem_size,
4581 ipa3_get_gsi_ver(ipa3_res.ipa_hw_type));
Amir Levy9659e592016-10-27 18:08:27 +03004582 if (result) {
4583 IPAERR("Failed to enable GSI FW\n");
4584 release_firmware(fw);
4585 return result;
4586 }
4587
4588 release_firmware(fw);
4589
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004590 IPADBG("Manual FW loading process is complete\n");
Amir Levy9659e592016-10-27 18:08:27 +03004591 return 0;
4592}
4593
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004594static int ipa3_pil_load_ipa_fws(void)
Amir Levy9659e592016-10-27 18:08:27 +03004595{
4596 void *subsystem_get_retval = NULL;
4597
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004598 IPADBG("PIL FW loading process initiated\n");
Amir Levy9659e592016-10-27 18:08:27 +03004599
4600 subsystem_get_retval = subsystem_get(IPA_SUBSYSTEM_NAME);
4601 if (IS_ERR_OR_NULL(subsystem_get_retval)) {
4602 IPAERR("Unable to trigger PIL process for FW loading\n");
4603 return -EINVAL;
4604 }
4605
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004606 IPADBG("PIL FW loading process is complete\n");
Amir Levy9659e592016-10-27 18:08:27 +03004607 return 0;
4608}
4609
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004610static void ipa3_load_ipa_fw(struct work_struct *work)
4611{
4612 int result;
4613
4614 IPADBG("Entry\n");
4615
4616 IPA_ACTIVE_CLIENTS_INC_SIMPLE();
4617
4618 if (ipa3_is_msm_device() || (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5))
4619 result = ipa3_pil_load_ipa_fws();
4620 else
4621 result = ipa3_manual_load_ipa_fws();
4622
4623 IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
4624
4625 if (result) {
4626 IPAERR("IPA FW loading process has failed\n");
4627 return;
4628 }
4629 pr_info("IPA FW loaded successfully\n");
4630
4631 result = ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
4632 if (result)
4633 IPAERR("IPA post init failed %d\n", result);
4634}
4635
Amir Levy9659e592016-10-27 18:08:27 +03004636static ssize_t ipa3_write(struct file *file, const char __user *buf,
4637 size_t count, loff_t *ppos)
4638{
4639 unsigned long missing;
Amir Levy9659e592016-10-27 18:08:27 +03004640
Amir Levy2da9d452017-12-12 10:09:46 +02004641 char dbg_buff[32] = { 0 };
Amir Levy9659e592016-10-27 18:08:27 +03004642
4643 if (sizeof(dbg_buff) < count + 1)
4644 return -EFAULT;
4645
4646 missing = copy_from_user(dbg_buff, buf, count);
4647
4648 if (missing) {
4649 IPAERR("Unable to copy data from user\n");
4650 return -EFAULT;
4651 }
4652
Mohammed Javidbf4c8022017-08-07 23:15:48 +05304653 if (count > 0)
4654 dbg_buff[count - 1] = '\0';
4655
Amir Levy2da9d452017-12-12 10:09:46 +02004656 IPADBG("user input string %s\n", dbg_buff);
4657
Amir Levy9659e592016-10-27 18:08:27 +03004658 /* Prevent consequent calls from trying to load the FW again. */
4659 if (ipa3_is_ready())
4660 return count;
4661
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004662 /* Check MHI configuration on MDM devices */
4663 if (!ipa3_is_msm_device()) {
Amir Levy2da9d452017-12-12 10:09:46 +02004664
4665 if (strnstr(dbg_buff, "vlan", strlen(dbg_buff))) {
4666 if (strnstr(dbg_buff, "eth", strlen(dbg_buff)))
4667 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_EMAC] =
4668 true;
4669 if (strnstr(dbg_buff, "rndis", strlen(dbg_buff)))
4670 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_RNDIS] =
4671 true;
4672 if (strnstr(dbg_buff, "ecm", strlen(dbg_buff)))
4673 ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM] =
4674 true;
4675
4676 /*
4677 * when vlan mode is passed to our dev we expect
4678 * another write
4679 */
4680 return count;
4681 }
4682
Amir Levy54fe4d32017-03-16 11:21:49 +02004683 if (!strcasecmp(dbg_buff, "MHI")) {
4684 ipa3_ctx->ipa_config_is_mhi = true;
4685 pr_info(
Amir Levy2da9d452017-12-12 10:09:46 +02004686 "IPA is loading with MHI configuration\n");
4687 } else if (!strcmp(dbg_buff, "1\n")) {
Amir Levy54fe4d32017-03-16 11:21:49 +02004688 pr_info(
Amir Levy2da9d452017-12-12 10:09:46 +02004689 "IPA is loading with non MHI configuration\n");
4690 } else {
4691 IPAERR("got invalid string %s not loading FW\n",
4692 dbg_buff);
4693 return count;
Amir Levy54fe4d32017-03-16 11:21:49 +02004694 }
Amir Levy54fe4d32017-03-16 11:21:49 +02004695 }
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004696
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004697 queue_work(ipa3_ctx->transport_power_mgmt_wq,
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004698 &ipa3_fw_loading_work);
Ghanim Fodi03dcc272017-08-08 18:13:25 +03004699
Ghanim Fodia5f376a2017-10-17 18:14:53 +03004700 IPADBG("Scheduled a work to load IPA FW\n");
Amir Levy9659e592016-10-27 18:08:27 +03004701 return count;
4702}
4703
Skylar Chang48afa052017-10-25 09:32:57 -07004704/**
4705 * ipa3_tz_unlock_reg - Unlocks memory regions so that they become accessible
4706 * from AP.
4707 * @reg_info - Pointer to array of memory regions to unlock
4708 * @num_regs - Number of elements in the array
4709 *
4710 * Converts the input array of regions to a struct that TZ understands and
4711 * issues an SCM call.
4712 * Also flushes the memory cache to DDR in order to make sure that TZ sees the
4713 * correct data structure.
4714 *
4715 * Returns: 0 on success, negative on failure
4716 */
4717int ipa3_tz_unlock_reg(struct ipa_tz_unlock_reg_info *reg_info, u16 num_regs)
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004718{
4719 int i, size, ret, resp;
4720 struct tz_smmu_ipa_protect_region_iovec_s *ipa_tz_unlock_vec;
4721 struct tz_smmu_ipa_protect_region_s cmd_buf;
Skylar Chang3a696ba2017-10-25 09:35:07 -07004722 struct scm_desc desc = {0};
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004723
Skylar Chang48afa052017-10-25 09:32:57 -07004724 if (reg_info == NULL || num_regs == 0) {
4725 IPAERR("Bad parameters\n");
4726 return -EFAULT;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004727 }
Skylar Chang48afa052017-10-25 09:32:57 -07004728
4729 size = num_regs * sizeof(struct tz_smmu_ipa_protect_region_iovec_s);
4730 ipa_tz_unlock_vec = kzalloc(PAGE_ALIGN(size), GFP_KERNEL);
4731 if (ipa_tz_unlock_vec == NULL)
4732 return -ENOMEM;
4733
4734 for (i = 0; i < num_regs; i++) {
4735 ipa_tz_unlock_vec[i].input_addr = reg_info[i].reg_addr ^
4736 (reg_info[i].reg_addr & 0xFFF);
4737 ipa_tz_unlock_vec[i].output_addr = reg_info[i].reg_addr ^
4738 (reg_info[i].reg_addr & 0xFFF);
4739 ipa_tz_unlock_vec[i].size = reg_info[i].size;
4740 ipa_tz_unlock_vec[i].attr = IPA_TZ_UNLOCK_ATTRIBUTE;
4741 }
4742
4743 /* pass physical address of command buffer */
4744 cmd_buf.iovec_buf = virt_to_phys((void *)ipa_tz_unlock_vec);
4745 cmd_buf.size_bytes = size;
4746
4747 /* flush cache to DDR */
4748 __cpuc_flush_dcache_area((void *)ipa_tz_unlock_vec, size);
4749 outer_flush_range(cmd_buf.iovec_buf, cmd_buf.iovec_buf + size);
Skylar Chang3a696ba2017-10-25 09:35:07 -07004750 if (!is_scm_armv8())
4751 ret = scm_call(SCM_SVC_MP, TZ_MEM_PROTECT_REGION_ID,
4752 &cmd_buf, sizeof(cmd_buf), &resp, sizeof(resp));
4753 else {
4754 desc.args[0] = virt_to_phys((void *)ipa_tz_unlock_vec);
4755 desc.args[1] = size;
4756 desc.arginfo = SCM_ARGS(2, SCM_RO, SCM_VAL);
4757 ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
4758 TZ_MEM_PROTECT_REGION_ID), &desc);
4759 }
Skylar Chang48afa052017-10-25 09:32:57 -07004760
Skylar Chang48afa052017-10-25 09:32:57 -07004761 if (ret) {
4762 IPAERR("scm call SCM_SVC_MP failed: %d\n", ret);
4763 kfree(ipa_tz_unlock_vec);
4764 return -EFAULT;
4765 }
4766 kfree(ipa_tz_unlock_vec);
4767
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004768 return 0;
4769}
4770
Skylar Changcd3902d2017-03-27 18:08:27 -07004771static int ipa3_alloc_pkt_init(void)
4772{
4773 struct ipa_mem_buffer mem;
4774 struct ipahal_imm_cmd_pyld *cmd_pyld;
4775 struct ipahal_imm_cmd_ip_packet_init cmd = {0};
4776 int i;
4777
4778 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
4779 &cmd, false);
4780 if (!cmd_pyld) {
4781 IPAERR("failed to construct IMM cmd\n");
4782 return -ENOMEM;
4783 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -07004784 ipa3_ctx->pkt_init_imm_opcode = cmd_pyld->opcode;
Skylar Changcd3902d2017-03-27 18:08:27 -07004785
4786 mem.size = cmd_pyld->len * ipa3_ctx->ipa_num_pipes;
4787 mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
4788 &mem.phys_base, GFP_KERNEL);
4789 if (!mem.base) {
4790 IPAERR("failed to alloc DMA buff of size %d\n", mem.size);
4791 ipahal_destroy_imm_cmd(cmd_pyld);
4792 return -ENOMEM;
4793 }
4794 ipahal_destroy_imm_cmd(cmd_pyld);
4795
4796 memset(mem.base, 0, mem.size);
4797 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
4798 cmd.destination_pipe_index = i;
4799 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
4800 &cmd, false);
4801 if (!cmd_pyld) {
4802 IPAERR("failed to construct IMM cmd\n");
4803 dma_free_coherent(ipa3_ctx->pdev,
4804 mem.size,
4805 mem.base,
4806 mem.phys_base);
4807 return -ENOMEM;
4808 }
4809 memcpy(mem.base + i * cmd_pyld->len, cmd_pyld->data,
4810 cmd_pyld->len);
4811 ipa3_ctx->pkt_init_imm[i] = mem.phys_base + i * cmd_pyld->len;
4812 ipahal_destroy_imm_cmd(cmd_pyld);
4813 }
4814
4815 return 0;
4816}
4817
Amir Levy9659e592016-10-27 18:08:27 +03004818/**
4819* ipa3_pre_init() - Initialize the IPA Driver.
4820* This part contains all initialization which doesn't require IPA HW, such
4821* as structure allocations and initializations, register writes, etc.
4822*
4823* @resource_p: contain platform specific values from DST file
4824* @pdev: The platform device structure representing the IPA driver
4825*
4826* Function initialization process:
Amir Levy54fe4d32017-03-16 11:21:49 +02004827* Allocate memory for the driver context data struct
4828* Initializing the ipa3_ctx with :
Amir Levy9659e592016-10-27 18:08:27 +03004829* 1)parsed values from the dts file
4830* 2)parameters passed to the module initialization
4831* 3)read HW values(such as core memory size)
Amir Levy54fe4d32017-03-16 11:21:49 +02004832* Map IPA core registers to CPU memory
4833* Restart IPA core(HW reset)
4834* Initialize the look-aside caches(kmem_cache/slab) for filter,
Amir Levy9659e592016-10-27 18:08:27 +03004835* routing and IPA-tree
Amir Levy54fe4d32017-03-16 11:21:49 +02004836* Create memory pool with 4 objects for DMA operations(each object
Amir Levy9659e592016-10-27 18:08:27 +03004837* is 512Bytes long), this object will be use for tx(A5->IPA)
Amir Levy54fe4d32017-03-16 11:21:49 +02004838* Initialize lists head(routing, hdr, system pipes)
4839* Initialize mutexes (for ipa_ctx and NAT memory mutexes)
4840* Initialize spinlocks (for list related to A5<->IPA pipes)
4841* Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq"
4842* Initialize Red-Black-Tree(s) for handles of header,routing rule,
4843* routing table ,filtering rule
4844* Initialize the filter block by committing IPV4 and IPV6 default rules
4845* Create empty routing table in system memory(no committing)
4846* Create a char-device for IPA
4847* Initialize IPA RM (resource manager)
4848* Configure GSI registers (in GSI case)
Amir Levy9659e592016-10-27 18:08:27 +03004849*/
4850static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
4851 struct device *ipa_dev)
4852{
4853 int result = 0;
4854 int i;
Amir Levy9659e592016-10-27 18:08:27 +03004855 struct ipa3_rt_tbl_set *rset;
4856 struct ipa_active_client_logging_info log_info;
4857
4858 IPADBG("IPA Driver initialization started\n");
4859
4860 ipa3_ctx = kzalloc(sizeof(*ipa3_ctx), GFP_KERNEL);
4861 if (!ipa3_ctx) {
4862 IPAERR(":kzalloc err.\n");
4863 result = -ENOMEM;
4864 goto fail_mem_ctx;
4865 }
4866
4867 ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0);
Skylar Chang841c1452017-04-03 16:07:22 -07004868 if (ipa3_ctx->logbuf == NULL)
4869 IPAERR("failed to create IPC log, continue...\n");
Amir Levy9659e592016-10-27 18:08:27 +03004870
4871 ipa3_ctx->pdev = ipa_dev;
4872 ipa3_ctx->uc_pdev = ipa_dev;
4873 ipa3_ctx->smmu_present = smmu_info.present;
Michael Adisumarta93e97522017-10-06 15:49:46 -07004874 if (!ipa3_ctx->smmu_present) {
4875 for (i = 0; i < IPA_SMMU_CB_MAX; i++)
4876 ipa3_ctx->s1_bypass_arr[i] = true;
4877 } else {
Michael Adisumarta972e33e2017-10-20 15:24:27 -07004878 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] =
4879 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP];
Michael Adisumarta93e97522017-10-06 15:49:46 -07004880 }
4881
Amir Levy9659e592016-10-27 18:08:27 +03004882 ipa3_ctx->ipa_wrapper_base = resource_p->ipa_mem_base;
4883 ipa3_ctx->ipa_wrapper_size = resource_p->ipa_mem_size;
4884 ipa3_ctx->ipa_hw_type = resource_p->ipa_hw_type;
4885 ipa3_ctx->ipa3_hw_mode = resource_p->ipa3_hw_mode;
4886 ipa3_ctx->use_ipa_teth_bridge = resource_p->use_ipa_teth_bridge;
Amir Levy9659e592016-10-27 18:08:27 +03004887 ipa3_ctx->modem_cfg_emb_pipe_flt = resource_p->modem_cfg_emb_pipe_flt;
4888 ipa3_ctx->ipa_wdi2 = resource_p->ipa_wdi2;
4889 ipa3_ctx->use_64_bit_dma_mask = resource_p->use_64_bit_dma_mask;
4890 ipa3_ctx->wan_rx_ring_size = resource_p->wan_rx_ring_size;
4891 ipa3_ctx->lan_rx_ring_size = resource_p->lan_rx_ring_size;
4892 ipa3_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
4893 ipa3_ctx->tethered_flow_control = resource_p->tethered_flow_control;
Amir Levy9659e592016-10-27 18:08:27 +03004894 ipa3_ctx->ee = resource_p->ee;
4895 ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa;
4896 ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa;
Michael Adisumarta3e350812017-09-18 14:54:36 -07004897 ipa3_ctx->use_ipa_pm = resource_p->use_ipa_pm;
Amir Levy9659e592016-10-27 18:08:27 +03004898 ipa3_ctx->ipa3_active_clients_logging.log_rdy = false;
Ghanim Fodic823bc62017-10-21 17:29:53 +03004899 ipa3_ctx->mhi_evid_limits[0] = resource_p->mhi_evid_limits[0];
4900 ipa3_ctx->mhi_evid_limits[1] = resource_p->mhi_evid_limits[1];
Gidon Studinski3021a6f2016-11-10 12:48:48 +02004901 if (resource_p->ipa_tz_unlock_reg) {
4902 ipa3_ctx->ipa_tz_unlock_reg_num =
4903 resource_p->ipa_tz_unlock_reg_num;
4904 ipa3_ctx->ipa_tz_unlock_reg = kcalloc(
4905 ipa3_ctx->ipa_tz_unlock_reg_num,
4906 sizeof(*ipa3_ctx->ipa_tz_unlock_reg),
4907 GFP_KERNEL);
4908 if (ipa3_ctx->ipa_tz_unlock_reg == NULL) {
4909 result = -ENOMEM;
4910 goto fail_tz_unlock_reg;
4911 }
4912 for (i = 0; i < ipa3_ctx->ipa_tz_unlock_reg_num; i++) {
4913 ipa3_ctx->ipa_tz_unlock_reg[i].reg_addr =
4914 resource_p->ipa_tz_unlock_reg[i].reg_addr;
4915 ipa3_ctx->ipa_tz_unlock_reg[i].size =
4916 resource_p->ipa_tz_unlock_reg[i].size;
4917 }
4918 }
4919
4920 /* unlock registers for uc */
Skylar Chang48afa052017-10-25 09:32:57 -07004921 result = ipa3_tz_unlock_reg(ipa3_ctx->ipa_tz_unlock_reg,
4922 ipa3_ctx->ipa_tz_unlock_reg_num);
4923 if (result)
4924 IPAERR("Failed to unlock memory region using TZ\n");
Amir Levy9659e592016-10-27 18:08:27 +03004925
4926 /* default aggregation parameters */
4927 ipa3_ctx->aggregation_type = IPA_MBIM_16;
4928 ipa3_ctx->aggregation_byte_limit = 1;
4929 ipa3_ctx->aggregation_time_limit = 0;
4930
4931 ipa3_ctx->ctrl = kzalloc(sizeof(*ipa3_ctx->ctrl), GFP_KERNEL);
4932 if (!ipa3_ctx->ctrl) {
4933 IPAERR("memory allocation error for ctrl\n");
4934 result = -ENOMEM;
4935 goto fail_mem_ctrl;
4936 }
4937 result = ipa3_controller_static_bind(ipa3_ctx->ctrl,
4938 ipa3_ctx->ipa_hw_type);
4939 if (result) {
4940 IPAERR("fail to static bind IPA ctrl.\n");
4941 result = -EFAULT;
4942 goto fail_bind;
4943 }
4944
4945 result = ipa3_init_mem_partition(master_dev->of_node);
4946 if (result) {
4947 IPAERR(":ipa3_init_mem_partition failed!\n");
4948 result = -ENODEV;
4949 goto fail_init_mem_partition;
4950 }
4951
4952 if (ipa3_bus_scale_table) {
Ghanim Fodi6a831342017-03-07 18:19:15 +02004953 IPADBG("Use bus scaling info from device tree #usecases=%d\n",
4954 ipa3_bus_scale_table->num_usecases);
Amir Levy9659e592016-10-27 18:08:27 +03004955 ipa3_ctx->ctrl->msm_bus_data_ptr = ipa3_bus_scale_table;
4956 }
4957
Ghanim Fodi6a831342017-03-07 18:19:15 +02004958 /* get BUS handle */
4959 ipa3_ctx->ipa_bus_hdl =
4960 msm_bus_scale_register_client(
4961 ipa3_ctx->ctrl->msm_bus_data_ptr);
4962 if (!ipa3_ctx->ipa_bus_hdl) {
4963 IPAERR("fail to register with bus mgr!\n");
4964 result = -ENODEV;
4965 goto fail_bus_reg;
Amir Levy9659e592016-10-27 18:08:27 +03004966 }
4967
4968 /* get IPA clocks */
4969 result = ipa3_get_clks(master_dev);
4970 if (result)
4971 goto fail_clk;
4972
4973 /* init active_clients_log after getting ipa-clk */
4974 if (ipa3_active_clients_log_init())
4975 goto fail_init_active_client;
4976
4977 /* Enable ipa3_ctx->enable_clock_scaling */
4978 ipa3_ctx->enable_clock_scaling = 1;
4979 ipa3_ctx->curr_ipa_clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
4980
4981 /* enable IPA clocks explicitly to allow the initialization */
4982 ipa3_enable_clks();
4983
4984 /* setup IPA register access */
4985 IPADBG("Mapping 0x%x\n", resource_p->ipa_mem_base +
4986 ipa3_ctx->ctrl->ipa_reg_base_ofst);
4987 ipa3_ctx->mmio = ioremap(resource_p->ipa_mem_base +
4988 ipa3_ctx->ctrl->ipa_reg_base_ofst,
4989 resource_p->ipa_mem_size);
4990 if (!ipa3_ctx->mmio) {
4991 IPAERR(":ipa-base ioremap err.\n");
4992 result = -EFAULT;
4993 goto fail_remap;
4994 }
4995
4996 if (ipahal_init(ipa3_ctx->ipa_hw_type, ipa3_ctx->mmio,
4997 ipa3_ctx->pdev)) {
4998 IPAERR("fail to init ipahal\n");
4999 result = -EFAULT;
5000 goto fail_ipahal;
5001 }
5002
5003 result = ipa3_init_hw();
5004 if (result) {
5005 IPAERR(":error initializing HW.\n");
5006 result = -ENODEV;
5007 goto fail_init_hw;
5008 }
5009 IPADBG("IPA HW initialization sequence completed");
5010
5011 ipa3_ctx->ipa_num_pipes = ipa3_get_num_pipes();
5012 if (ipa3_ctx->ipa_num_pipes > IPA3_MAX_NUM_PIPES) {
5013 IPAERR("IPA has more pipes then supported! has %d, max %d\n",
5014 ipa3_ctx->ipa_num_pipes, IPA3_MAX_NUM_PIPES);
5015 result = -ENODEV;
5016 goto fail_init_hw;
5017 }
5018
Amir Levy9659e592016-10-27 18:08:27 +03005019 ipa3_ctx->ctrl->ipa_sram_read_settings();
5020 IPADBG("SRAM, size: 0x%x, restricted bytes: 0x%x\n",
5021 ipa3_ctx->smem_sz, ipa3_ctx->smem_restricted_bytes);
5022
5023 IPADBG("hdr_lcl=%u ip4_rt_hash=%u ip4_rt_nonhash=%u\n",
5024 ipa3_ctx->hdr_tbl_lcl, ipa3_ctx->ip4_rt_tbl_hash_lcl,
5025 ipa3_ctx->ip4_rt_tbl_nhash_lcl);
5026
5027 IPADBG("ip6_rt_hash=%u ip6_rt_nonhash=%u\n",
5028 ipa3_ctx->ip6_rt_tbl_hash_lcl, ipa3_ctx->ip6_rt_tbl_nhash_lcl);
5029
5030 IPADBG("ip4_flt_hash=%u ip4_flt_nonhash=%u\n",
5031 ipa3_ctx->ip4_flt_tbl_hash_lcl,
5032 ipa3_ctx->ip4_flt_tbl_nhash_lcl);
5033
5034 IPADBG("ip6_flt_hash=%u ip6_flt_nonhash=%u\n",
5035 ipa3_ctx->ip6_flt_tbl_hash_lcl,
5036 ipa3_ctx->ip6_flt_tbl_nhash_lcl);
5037
5038 if (ipa3_ctx->smem_reqd_sz > ipa3_ctx->smem_sz) {
5039 IPAERR("SW expect more core memory, needed %d, avail %d\n",
5040 ipa3_ctx->smem_reqd_sz, ipa3_ctx->smem_sz);
5041 result = -ENOMEM;
5042 goto fail_init_hw;
5043 }
5044
5045 mutex_init(&ipa3_ctx->ipa3_active_clients.mutex);
Amir Levy9659e592016-10-27 18:08:27 +03005046 IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE");
5047 ipa3_active_clients_log_inc(&log_info, false);
Skylar Chang242952b2017-07-20 15:04:05 -07005048 atomic_set(&ipa3_ctx->ipa3_active_clients.cnt, 1);
Amir Levy9659e592016-10-27 18:08:27 +03005049
Amir Levy9659e592016-10-27 18:08:27 +03005050 /* Create workqueues for power management */
5051 ipa3_ctx->power_mgmt_wq =
5052 create_singlethread_workqueue("ipa_power_mgmt");
5053 if (!ipa3_ctx->power_mgmt_wq) {
5054 IPAERR("failed to create power mgmt wq\n");
5055 result = -ENOMEM;
5056 goto fail_init_hw;
5057 }
5058
5059 ipa3_ctx->transport_power_mgmt_wq =
5060 create_singlethread_workqueue("transport_power_mgmt");
5061 if (!ipa3_ctx->transport_power_mgmt_wq) {
5062 IPAERR("failed to create transport power mgmt wq\n");
5063 result = -ENOMEM;
5064 goto fail_create_transport_wq;
5065 }
5066
Sridhar Ancha99b505b2016-04-21 23:11:10 +05305067 mutex_init(&ipa3_ctx->transport_pm.transport_pm_mutex);
Amir Levy9659e592016-10-27 18:08:27 +03005068
5069 /* init the lookaside cache */
5070 ipa3_ctx->flt_rule_cache = kmem_cache_create("IPA_FLT",
5071 sizeof(struct ipa3_flt_entry), 0, 0, NULL);
5072 if (!ipa3_ctx->flt_rule_cache) {
5073 IPAERR(":ipa flt cache create failed\n");
5074 result = -ENOMEM;
5075 goto fail_flt_rule_cache;
5076 }
5077 ipa3_ctx->rt_rule_cache = kmem_cache_create("IPA_RT",
5078 sizeof(struct ipa3_rt_entry), 0, 0, NULL);
5079 if (!ipa3_ctx->rt_rule_cache) {
5080 IPAERR(":ipa rt cache create failed\n");
5081 result = -ENOMEM;
5082 goto fail_rt_rule_cache;
5083 }
5084 ipa3_ctx->hdr_cache = kmem_cache_create("IPA_HDR",
5085 sizeof(struct ipa3_hdr_entry), 0, 0, NULL);
5086 if (!ipa3_ctx->hdr_cache) {
5087 IPAERR(":ipa hdr cache create failed\n");
5088 result = -ENOMEM;
5089 goto fail_hdr_cache;
5090 }
5091 ipa3_ctx->hdr_offset_cache =
5092 kmem_cache_create("IPA_HDR_OFFSET",
5093 sizeof(struct ipa_hdr_offset_entry), 0, 0, NULL);
5094 if (!ipa3_ctx->hdr_offset_cache) {
5095 IPAERR(":ipa hdr off cache create failed\n");
5096 result = -ENOMEM;
5097 goto fail_hdr_offset_cache;
5098 }
5099 ipa3_ctx->hdr_proc_ctx_cache = kmem_cache_create("IPA_HDR_PROC_CTX",
5100 sizeof(struct ipa3_hdr_proc_ctx_entry), 0, 0, NULL);
5101 if (!ipa3_ctx->hdr_proc_ctx_cache) {
5102 IPAERR(":ipa hdr proc ctx cache create failed\n");
5103 result = -ENOMEM;
5104 goto fail_hdr_proc_ctx_cache;
5105 }
5106 ipa3_ctx->hdr_proc_ctx_offset_cache =
5107 kmem_cache_create("IPA_HDR_PROC_CTX_OFFSET",
5108 sizeof(struct ipa3_hdr_proc_ctx_offset_entry), 0, 0, NULL);
5109 if (!ipa3_ctx->hdr_proc_ctx_offset_cache) {
5110 IPAERR(":ipa hdr proc ctx off cache create failed\n");
5111 result = -ENOMEM;
5112 goto fail_hdr_proc_ctx_offset_cache;
5113 }
5114 ipa3_ctx->rt_tbl_cache = kmem_cache_create("IPA_RT_TBL",
5115 sizeof(struct ipa3_rt_tbl), 0, 0, NULL);
5116 if (!ipa3_ctx->rt_tbl_cache) {
5117 IPAERR(":ipa rt tbl cache create failed\n");
5118 result = -ENOMEM;
5119 goto fail_rt_tbl_cache;
5120 }
5121 ipa3_ctx->tx_pkt_wrapper_cache =
5122 kmem_cache_create("IPA_TX_PKT_WRAPPER",
5123 sizeof(struct ipa3_tx_pkt_wrapper), 0, 0, NULL);
5124 if (!ipa3_ctx->tx_pkt_wrapper_cache) {
5125 IPAERR(":ipa tx pkt wrapper cache create failed\n");
5126 result = -ENOMEM;
5127 goto fail_tx_pkt_wrapper_cache;
5128 }
5129 ipa3_ctx->rx_pkt_wrapper_cache =
5130 kmem_cache_create("IPA_RX_PKT_WRAPPER",
5131 sizeof(struct ipa3_rx_pkt_wrapper), 0, 0, NULL);
5132 if (!ipa3_ctx->rx_pkt_wrapper_cache) {
5133 IPAERR(":ipa rx pkt wrapper cache create failed\n");
5134 result = -ENOMEM;
5135 goto fail_rx_pkt_wrapper_cache;
5136 }
5137
Skylar Chang6c4bec92017-04-21 16:10:14 -07005138 /* allocate memory for DMA_TASK workaround */
5139 result = ipa3_allocate_dma_task_for_gsi();
5140 if (result) {
5141 IPAERR("failed to allocate dma task\n");
5142 goto fail_dma_task;
5143 }
5144
Amir Levy9659e592016-10-27 18:08:27 +03005145 /* init the various list heads */
5146 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_hdr_entry_list);
5147 for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
5148 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_offset_list[i]);
5149 INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_free_offset_list[i]);
5150 }
5151 INIT_LIST_HEAD(&ipa3_ctx->hdr_proc_ctx_tbl.head_proc_ctx_entry_list);
5152 for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) {
5153 INIT_LIST_HEAD(&ipa3_ctx->hdr_proc_ctx_tbl.head_offset_list[i]);
5154 INIT_LIST_HEAD(&ipa3_ctx->
5155 hdr_proc_ctx_tbl.head_free_offset_list[i]);
5156 }
5157 INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005158 idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005159 INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005160 idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005161
5162 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
5163 INIT_LIST_HEAD(&rset->head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005164 idr_init(&rset->rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005165 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
5166 INIT_LIST_HEAD(&rset->head_rt_tbl_list);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005167 idr_init(&rset->rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +03005168
5169 INIT_LIST_HEAD(&ipa3_ctx->intf_list);
5170 INIT_LIST_HEAD(&ipa3_ctx->msg_list);
5171 INIT_LIST_HEAD(&ipa3_ctx->pull_msg_list);
5172 init_waitqueue_head(&ipa3_ctx->msg_waitq);
5173 mutex_init(&ipa3_ctx->msg_lock);
5174
5175 mutex_init(&ipa3_ctx->lock);
Skylar Changfb792c62017-08-17 12:53:23 -07005176 mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex);
Mohammed Javidb4b5ef42017-08-29 01:05:46 +05305177 mutex_init(&ipa3_ctx->ipa_cne_evt_lock);
Mohammed Javid05b05d02017-11-13 23:43:27 +05305178 ipa3_ctx->q6_proxy_clk_vote_cnt = 0;
Amir Levy9659e592016-10-27 18:08:27 +03005179
5180 idr_init(&ipa3_ctx->ipa_idr);
5181 spin_lock_init(&ipa3_ctx->idr_lock);
5182
5183 /* wlan related member */
5184 memset(&ipa3_ctx->wc_memb, 0, sizeof(ipa3_ctx->wc_memb));
5185 spin_lock_init(&ipa3_ctx->wc_memb.wlan_spinlock);
5186 spin_lock_init(&ipa3_ctx->wc_memb.ipa_tx_mul_spinlock);
5187 INIT_LIST_HEAD(&ipa3_ctx->wc_memb.wlan_comm_desc_list);
5188
Amir Levy9659e592016-10-27 18:08:27 +03005189 ipa3_ctx->class = class_create(THIS_MODULE, DRV_NAME);
5190
5191 result = alloc_chrdev_region(&ipa3_ctx->dev_num, 0, 1, DRV_NAME);
5192 if (result) {
5193 IPAERR("alloc_chrdev_region err.\n");
5194 result = -ENODEV;
5195 goto fail_alloc_chrdev_region;
5196 }
5197
5198 ipa3_ctx->dev = device_create(ipa3_ctx->class, NULL, ipa3_ctx->dev_num,
5199 ipa3_ctx, DRV_NAME);
5200 if (IS_ERR(ipa3_ctx->dev)) {
5201 IPAERR(":device_create err.\n");
5202 result = -ENODEV;
5203 goto fail_device_create;
5204 }
5205
Amir Levy479cfdd2017-10-26 12:23:14 +03005206 if (ipa3_nat_ipv6ct_init_devices()) {
5207 IPAERR("unable to init NAT and IPv6CT devices\n");
Amir Levy9659e592016-10-27 18:08:27 +03005208 result = -ENODEV;
Amir Levy479cfdd2017-10-26 12:23:14 +03005209 goto fail_nat_ipv6ct_init_dev;
Amir Levy9659e592016-10-27 18:08:27 +03005210 }
5211
5212 /* Create a wakeup source. */
5213 wakeup_source_init(&ipa3_ctx->w_lock, "IPA_WS");
5214 spin_lock_init(&ipa3_ctx->wakelock_ref_cnt.spinlock);
5215
Michael Adisumarta3e350812017-09-18 14:54:36 -07005216 /* Initialize Power Management framework */
5217 if (ipa3_ctx->use_ipa_pm) {
5218 result = ipa_pm_init(&ipa3_res.pm_init);
5219 if (result) {
5220 IPAERR("IPA PM initialization failed (%d)\n", -result);
5221 result = -ENODEV;
5222 goto fail_ipa_rm_init;
5223 }
5224 IPADBG("IPA resource manager initialized");
5225 } else {
5226 result = ipa_rm_initialize();
5227 if (result) {
5228 IPAERR("RM initialization failed (%d)\n", -result);
5229 result = -ENODEV;
5230 goto fail_ipa_rm_init;
5231 }
5232 IPADBG("IPA resource manager initialized");
Amir Levy9659e592016-10-27 18:08:27 +03005233
Michael Adisumarta3e350812017-09-18 14:54:36 -07005234 result = ipa3_create_apps_resource();
5235 if (result) {
5236 IPAERR("Failed to create APPS_CONS resource\n");
5237 result = -ENODEV;
5238 goto fail_create_apps_resource;
5239 }
Amir Levy9659e592016-10-27 18:08:27 +03005240 }
5241
Skylar Changcd3902d2017-03-27 18:08:27 -07005242 result = ipa3_alloc_pkt_init();
5243 if (result) {
5244 IPAERR("Failed to alloc pkt_init payload\n");
5245 result = -ENODEV;
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005246 goto fail_allok_pkt_init;
Skylar Changcd3902d2017-03-27 18:08:27 -07005247 }
5248
Amir Levy12ef0912016-08-30 09:27:34 +03005249 if (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5)
5250 ipa3_enable_dcd();
5251
Amir Levy9659e592016-10-27 18:08:27 +03005252 INIT_LIST_HEAD(&ipa3_ctx->ipa_ready_cb_list);
5253
5254 init_completion(&ipa3_ctx->init_completion_obj);
Skylar Chang0c17c7d2016-10-31 09:57:54 -07005255 init_completion(&ipa3_ctx->uc_loaded_completion_obj);
Amir Levy9659e592016-10-27 18:08:27 +03005256
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005257 result = ipa3_dma_setup();
5258 if (result) {
5259 IPAERR("Failed to setup IPA DMA\n");
5260 result = -ENODEV;
5261 goto fail_ipa_dma_setup;
5262 }
5263
Amir Levy9659e592016-10-27 18:08:27 +03005264 /*
Amir Levya59ed3f2017-03-05 17:30:55 +02005265 * We can't register the GSI driver yet, as it expects
Amir Levy9659e592016-10-27 18:08:27 +03005266 * the GSI FW to be up and running before the registration.
Amir Levya59ed3f2017-03-05 17:30:55 +02005267 *
5268 * For IPA3.0, the GSI configuration is done by the GSI driver.
5269 * For IPA3.1 (and on), the GSI configuration is done by TZ.
Amir Levy9659e592016-10-27 18:08:27 +03005270 */
Amir Levya59ed3f2017-03-05 17:30:55 +02005271 if (ipa3_ctx->ipa_hw_type == IPA_HW_v3_0) {
5272 result = ipa3_gsi_pre_fw_load_init();
5273 if (result) {
5274 IPAERR("gsi pre FW loading config failed\n");
5275 result = -ENODEV;
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005276 goto fail_gsi_pre_fw_load_init;
Amir Levy9659e592016-10-27 18:08:27 +03005277 }
5278 }
Amir Levy9659e592016-10-27 18:08:27 +03005279
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305280 cdev_init(&ipa3_ctx->cdev, &ipa3_drv_fops);
5281 ipa3_ctx->cdev.owner = THIS_MODULE;
5282 ipa3_ctx->cdev.ops = &ipa3_drv_fops; /* from LDD3 */
5283
5284 result = cdev_add(&ipa3_ctx->cdev, ipa3_ctx->dev_num, 1);
5285 if (result) {
5286 IPAERR(":cdev_add err=%d\n", -result);
5287 result = -ENODEV;
5288 goto fail_cdev_add;
5289 }
5290 IPADBG("ipa cdev added successful. major:%d minor:%d\n",
5291 MAJOR(ipa3_ctx->dev_num),
5292 MINOR(ipa3_ctx->dev_num));
Amir Levy9659e592016-10-27 18:08:27 +03005293 return 0;
5294
Utkarsh Saxenaded78142017-05-03 14:04:30 +05305295fail_cdev_add:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005296fail_gsi_pre_fw_load_init:
5297 ipa3_dma_shutdown();
5298fail_ipa_dma_setup:
5299fail_allok_pkt_init:
5300 if (ipa3_ctx->use_ipa_pm)
5301 ipa_pm_destroy();
5302 else
Michael Adisumarta3e350812017-09-18 14:54:36 -07005303 ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
Amir Levy9659e592016-10-27 18:08:27 +03005304fail_create_apps_resource:
Michael Adisumarta3e350812017-09-18 14:54:36 -07005305 if (!ipa3_ctx->use_ipa_pm)
5306 ipa_rm_exit();
Amir Levy9659e592016-10-27 18:08:27 +03005307fail_ipa_rm_init:
Amir Levy479cfdd2017-10-26 12:23:14 +03005308 ipa3_nat_ipv6ct_destroy_devices();
5309fail_nat_ipv6ct_init_dev:
Amir Levy9659e592016-10-27 18:08:27 +03005310 device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
5311fail_device_create:
5312 unregister_chrdev_region(ipa3_ctx->dev_num, 1);
5313fail_alloc_chrdev_region:
Ghanim Fodie6bb7a82017-10-02 17:59:58 +03005314 idr_destroy(&ipa3_ctx->ipa_idr);
Skylar Chang0c37f5f2017-07-24 10:22:53 -07005315 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
5316 idr_destroy(&rset->rule_ids);
5317 rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
5318 idr_destroy(&rset->rule_ids);
5319 idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
5320 idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
Skylar Chang6c4bec92017-04-21 16:10:14 -07005321 ipa3_free_dma_task_for_gsi();
5322fail_dma_task:
Amir Levy9659e592016-10-27 18:08:27 +03005323 kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
5324fail_rx_pkt_wrapper_cache:
5325 kmem_cache_destroy(ipa3_ctx->tx_pkt_wrapper_cache);
5326fail_tx_pkt_wrapper_cache:
5327 kmem_cache_destroy(ipa3_ctx->rt_tbl_cache);
5328fail_rt_tbl_cache:
5329 kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_offset_cache);
5330fail_hdr_proc_ctx_offset_cache:
5331 kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_cache);
5332fail_hdr_proc_ctx_cache:
5333 kmem_cache_destroy(ipa3_ctx->hdr_offset_cache);
5334fail_hdr_offset_cache:
5335 kmem_cache_destroy(ipa3_ctx->hdr_cache);
5336fail_hdr_cache:
5337 kmem_cache_destroy(ipa3_ctx->rt_rule_cache);
5338fail_rt_rule_cache:
5339 kmem_cache_destroy(ipa3_ctx->flt_rule_cache);
5340fail_flt_rule_cache:
5341 destroy_workqueue(ipa3_ctx->transport_power_mgmt_wq);
5342fail_create_transport_wq:
5343 destroy_workqueue(ipa3_ctx->power_mgmt_wq);
5344fail_init_hw:
5345 ipahal_destroy();
5346fail_ipahal:
5347 iounmap(ipa3_ctx->mmio);
5348fail_remap:
5349 ipa3_disable_clks();
5350 ipa3_active_clients_log_destroy();
5351fail_init_active_client:
Ghanim Fodi6a831342017-03-07 18:19:15 +02005352 if (ipa3_clk)
5353 clk_put(ipa3_clk);
5354 ipa3_clk = NULL;
Amir Levy9659e592016-10-27 18:08:27 +03005355fail_clk:
5356 msm_bus_scale_unregister_client(ipa3_ctx->ipa_bus_hdl);
5357fail_bus_reg:
Ghanim Fodi6a831342017-03-07 18:19:15 +02005358 if (ipa3_bus_scale_table) {
5359 msm_bus_cl_clear_pdata(ipa3_bus_scale_table);
5360 ipa3_bus_scale_table = NULL;
5361 }
Amir Levy9659e592016-10-27 18:08:27 +03005362fail_init_mem_partition:
5363fail_bind:
5364 kfree(ipa3_ctx->ctrl);
5365fail_mem_ctrl:
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005366 kfree(ipa3_ctx->ipa_tz_unlock_reg);
5367fail_tz_unlock_reg:
Skylar Chang841c1452017-04-03 16:07:22 -07005368 if (ipa3_ctx->logbuf)
5369 ipc_log_context_destroy(ipa3_ctx->logbuf);
Amir Levy9659e592016-10-27 18:08:27 +03005370 kfree(ipa3_ctx);
5371 ipa3_ctx = NULL;
5372fail_mem_ctx:
5373 return result;
5374}
5375
Michael Adisumarta3e350812017-09-18 14:54:36 -07005376bool ipa_pm_is_used(void)
5377{
5378 return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
5379}
5380
5381static int get_ipa_dts_pm_info(struct platform_device *pdev,
5382 struct ipa3_plat_drv_res *ipa_drv_res)
5383{
5384 int result;
5385 int i, j;
5386
5387 ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
5388 "qcom,use-ipa-pm");
5389 IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
5390 if (!ipa_drv_res->use_ipa_pm)
5391 return 0;
5392
5393 result = of_property_read_u32(pdev->dev.of_node,
5394 "qcom,msm-bus,num-cases",
5395 &ipa_drv_res->pm_init.threshold_size);
5396 /* No vote is ignored */
5397 ipa_drv_res->pm_init.threshold_size -= 2;
5398 if (result || ipa_drv_res->pm_init.threshold_size >
5399 IPA_PM_THRESHOLD_MAX) {
5400 IPAERR("invalid property qcom,msm-bus,num-cases %d\n",
5401 ipa_drv_res->pm_init.threshold_size);
5402 return -EFAULT;
5403 }
5404
5405 result = of_property_read_u32_array(pdev->dev.of_node,
5406 "qcom,throughput-threshold",
5407 ipa_drv_res->pm_init.default_threshold,
5408 ipa_drv_res->pm_init.threshold_size);
5409 if (result) {
5410 IPAERR("failed to read qcom,throughput-thresholds\n");
5411 return -EFAULT;
5412 }
5413
5414 result = of_property_count_strings(pdev->dev.of_node,
5415 "qcom,scaling-exceptions");
5416 if (result < 0) {
5417 IPADBG("no exception list for ipa pm\n");
5418 result = 0;
5419 }
5420
5421 if (result % (ipa_drv_res->pm_init.threshold_size + 1)) {
5422 IPAERR("failed to read qcom,scaling-exceptions\n");
5423 return -EFAULT;
5424 }
5425
5426 ipa_drv_res->pm_init.exception_size = result /
5427 (ipa_drv_res->pm_init.threshold_size + 1);
5428 if (ipa_drv_res->pm_init.exception_size >=
5429 IPA_PM_EXCEPTION_MAX) {
5430 IPAERR("exception list larger then max %d\n",
5431 ipa_drv_res->pm_init.exception_size);
5432 return -EFAULT;
5433 }
5434
5435 for (i = 0; i < ipa_drv_res->pm_init.exception_size; i++) {
5436 struct ipa_pm_exception *ex = ipa_drv_res->pm_init.exceptions;
5437
5438 result = of_property_read_string_index(pdev->dev.of_node,
5439 "qcom,scaling-exceptions",
5440 i * ipa_drv_res->pm_init.threshold_size,
5441 &ex[i].usecase);
5442 if (result) {
5443 IPAERR("failed to read qcom,scaling-exceptions");
5444 return -EFAULT;
5445 }
5446
5447 for (j = 0; j < ipa_drv_res->pm_init.threshold_size; j++) {
5448 const char *str;
5449
5450 result = of_property_read_string_index(
5451 pdev->dev.of_node,
5452 "qcom,scaling-exceptions",
5453 i * ipa_drv_res->pm_init.threshold_size + j + 1,
5454 &str);
5455 if (result) {
5456 IPAERR("failed to read qcom,scaling-exceptions"
5457 );
5458 return -EFAULT;
5459 }
5460
5461 if (kstrtou32(str, 0, &ex[i].threshold[j])) {
5462 IPAERR("error str=%s\n", str);
5463 return -EFAULT;
5464 }
5465 }
5466 }
5467
5468 return 0;
5469}
5470
Amir Levy9659e592016-10-27 18:08:27 +03005471static int get_ipa_dts_configuration(struct platform_device *pdev,
5472 struct ipa3_plat_drv_res *ipa_drv_res)
5473{
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005474 int i, result, pos;
Amir Levy9659e592016-10-27 18:08:27 +03005475 struct resource *resource;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005476 u32 *ipa_tz_unlock_reg;
5477 int elem_num;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005478 u32 mhi_evid_limits[2];
Amir Levy9659e592016-10-27 18:08:27 +03005479
5480 /* initialize ipa3_res */
5481 ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
5482 ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
5483 ipa_drv_res->ipa_hw_type = 0;
5484 ipa_drv_res->ipa3_hw_mode = 0;
Amir Levy9659e592016-10-27 18:08:27 +03005485 ipa_drv_res->modem_cfg_emb_pipe_flt = false;
5486 ipa_drv_res->ipa_wdi2 = false;
5487 ipa_drv_res->use_64_bit_dma_mask = false;
Ghanim Fodi6a831342017-03-07 18:19:15 +02005488 ipa_drv_res->use_bw_vote = false;
Amir Levy9659e592016-10-27 18:08:27 +03005489 ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
5490 ipa_drv_res->lan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
5491 ipa_drv_res->apply_rg10_wa = false;
5492 ipa_drv_res->gsi_ch20_wa = false;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005493 ipa_drv_res->ipa_tz_unlock_reg_num = 0;
5494 ipa_drv_res->ipa_tz_unlock_reg = NULL;
Ghanim Fodic823bc62017-10-21 17:29:53 +03005495 ipa_drv_res->mhi_evid_limits[0] = IPA_MHI_GSI_EVENT_RING_ID_START;
5496 ipa_drv_res->mhi_evid_limits[1] = IPA_MHI_GSI_EVENT_RING_ID_END;
Amir Levy9659e592016-10-27 18:08:27 +03005497
5498 /* Get IPA HW Version */
5499 result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver",
5500 &ipa_drv_res->ipa_hw_type);
5501 if ((result) || (ipa_drv_res->ipa_hw_type == 0)) {
5502 IPAERR(":get resource failed for ipa-hw-ver!\n");
5503 return -ENODEV;
5504 }
5505 IPADBG(": ipa_hw_type = %d", ipa_drv_res->ipa_hw_type);
5506
5507 if (ipa_drv_res->ipa_hw_type < IPA_HW_v3_0) {
5508 IPAERR(":IPA version below 3.0 not supported!\n");
5509 return -ENODEV;
5510 }
5511
5512 /* Get IPA HW mode */
5513 result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-mode",
5514 &ipa_drv_res->ipa3_hw_mode);
5515 if (result)
5516 IPADBG("using default (IPA_MODE_NORMAL) for ipa-hw-mode\n");
5517 else
5518 IPADBG(": found ipa_drv_res->ipa3_hw_mode = %d",
5519 ipa_drv_res->ipa3_hw_mode);
5520
5521 /* Get IPA WAN / LAN RX pool size */
5522 result = of_property_read_u32(pdev->dev.of_node,
5523 "qcom,wan-rx-ring-size",
5524 &ipa_drv_res->wan_rx_ring_size);
5525 if (result)
5526 IPADBG("using default for wan-rx-ring-size = %u\n",
5527 ipa_drv_res->wan_rx_ring_size);
5528 else
5529 IPADBG(": found ipa_drv_res->wan-rx-ring-size = %u",
5530 ipa_drv_res->wan_rx_ring_size);
5531
5532 result = of_property_read_u32(pdev->dev.of_node,
5533 "qcom,lan-rx-ring-size",
5534 &ipa_drv_res->lan_rx_ring_size);
5535 if (result)
5536 IPADBG("using default for lan-rx-ring-size = %u\n",
5537 ipa_drv_res->lan_rx_ring_size);
5538 else
5539 IPADBG(": found ipa_drv_res->lan-rx-ring-size = %u",
5540 ipa_drv_res->lan_rx_ring_size);
5541
5542 ipa_drv_res->use_ipa_teth_bridge =
5543 of_property_read_bool(pdev->dev.of_node,
5544 "qcom,use-ipa-tethering-bridge");
5545 IPADBG(": using TBDr = %s",
5546 ipa_drv_res->use_ipa_teth_bridge
5547 ? "True" : "False");
5548
Amir Levy9659e592016-10-27 18:08:27 +03005549 ipa_drv_res->modem_cfg_emb_pipe_flt =
5550 of_property_read_bool(pdev->dev.of_node,
5551 "qcom,modem-cfg-emb-pipe-flt");
5552 IPADBG(": modem configure embedded pipe filtering = %s\n",
5553 ipa_drv_res->modem_cfg_emb_pipe_flt
5554 ? "True" : "False");
5555
5556 ipa_drv_res->ipa_wdi2 =
5557 of_property_read_bool(pdev->dev.of_node,
5558 "qcom,ipa-wdi2");
5559 IPADBG(": WDI-2.0 = %s\n",
5560 ipa_drv_res->ipa_wdi2
5561 ? "True" : "False");
5562
5563 ipa_drv_res->use_64_bit_dma_mask =
5564 of_property_read_bool(pdev->dev.of_node,
5565 "qcom,use-64-bit-dma-mask");
5566 IPADBG(": use_64_bit_dma_mask = %s\n",
5567 ipa_drv_res->use_64_bit_dma_mask
5568 ? "True" : "False");
5569
Ghanim Fodi6a831342017-03-07 18:19:15 +02005570 ipa_drv_res->use_bw_vote =
5571 of_property_read_bool(pdev->dev.of_node,
5572 "qcom,bandwidth-vote-for-ipa");
5573 IPADBG(": use_bw_vote = %s\n",
5574 ipa_drv_res->use_bw_vote
5575 ? "True" : "False");
5576
Amir Levy9659e592016-10-27 18:08:27 +03005577 ipa_drv_res->skip_uc_pipe_reset =
5578 of_property_read_bool(pdev->dev.of_node,
5579 "qcom,skip-uc-pipe-reset");
5580 IPADBG(": skip uC pipe reset = %s\n",
5581 ipa_drv_res->skip_uc_pipe_reset
5582 ? "True" : "False");
5583
5584 ipa_drv_res->tethered_flow_control =
5585 of_property_read_bool(pdev->dev.of_node,
5586 "qcom,tethered-flow-control");
5587 IPADBG(": Use apps based flow control = %s\n",
5588 ipa_drv_res->tethered_flow_control
5589 ? "True" : "False");
5590
Amir Levy9659e592016-10-27 18:08:27 +03005591 /* Get IPA wrapper address */
5592 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5593 "ipa-base");
5594 if (!resource) {
5595 IPAERR(":get resource failed for ipa-base!\n");
5596 return -ENODEV;
5597 }
5598 ipa_drv_res->ipa_mem_base = resource->start;
5599 ipa_drv_res->ipa_mem_size = resource_size(resource);
5600 IPADBG(": ipa-base = 0x%x, size = 0x%x\n",
5601 ipa_drv_res->ipa_mem_base,
5602 ipa_drv_res->ipa_mem_size);
5603
5604 smmu_info.ipa_base = ipa_drv_res->ipa_mem_base;
5605 smmu_info.ipa_size = ipa_drv_res->ipa_mem_size;
5606
Amir Levya59ed3f2017-03-05 17:30:55 +02005607 /* Get IPA GSI address */
5608 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5609 "gsi-base");
5610 if (!resource) {
5611 IPAERR(":get resource failed for gsi-base!\n");
5612 return -ENODEV;
Amir Levy9659e592016-10-27 18:08:27 +03005613 }
Amir Levya59ed3f2017-03-05 17:30:55 +02005614 ipa_drv_res->transport_mem_base = resource->start;
5615 ipa_drv_res->transport_mem_size = resource_size(resource);
5616 IPADBG(": gsi-base = 0x%x, size = 0x%x\n",
5617 ipa_drv_res->transport_mem_base,
5618 ipa_drv_res->transport_mem_size);
5619
5620 /* Get IPA GSI IRQ number */
5621 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
5622 "gsi-irq");
5623 if (!resource) {
5624 IPAERR(":get resource failed for gsi-irq!\n");
5625 return -ENODEV;
5626 }
5627 ipa_drv_res->transport_irq = resource->start;
5628 IPADBG(": gsi-irq = %d\n", ipa_drv_res->transport_irq);
Amir Levy9659e592016-10-27 18:08:27 +03005629
5630 /* Get IPA pipe mem start ofst */
5631 resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5632 "ipa-pipe-mem");
5633 if (!resource) {
5634 IPADBG(":not using pipe memory - resource nonexisting\n");
5635 } else {
5636 ipa_drv_res->ipa_pipe_mem_start_ofst = resource->start;
5637 ipa_drv_res->ipa_pipe_mem_size = resource_size(resource);
5638 IPADBG(":using pipe memory - at 0x%x of size 0x%x\n",
5639 ipa_drv_res->ipa_pipe_mem_start_ofst,
5640 ipa_drv_res->ipa_pipe_mem_size);
5641 }
5642
5643 /* Get IPA IRQ number */
5644 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
5645 "ipa-irq");
5646 if (!resource) {
5647 IPAERR(":get resource failed for ipa-irq!\n");
5648 return -ENODEV;
5649 }
5650 ipa_drv_res->ipa_irq = resource->start;
5651 IPADBG(":ipa-irq = %d\n", ipa_drv_res->ipa_irq);
5652
5653 result = of_property_read_u32(pdev->dev.of_node, "qcom,ee",
5654 &ipa_drv_res->ee);
5655 if (result)
5656 ipa_drv_res->ee = 0;
5657
5658 ipa_drv_res->apply_rg10_wa =
5659 of_property_read_bool(pdev->dev.of_node,
5660 "qcom,use-rg10-limitation-mitigation");
5661 IPADBG(": Use Register Group 10 limitation mitigation = %s\n",
5662 ipa_drv_res->apply_rg10_wa
5663 ? "True" : "False");
5664
5665 ipa_drv_res->gsi_ch20_wa =
5666 of_property_read_bool(pdev->dev.of_node,
5667 "qcom,do-not-use-ch-gsi-20");
5668 IPADBG(": GSI CH 20 WA is = %s\n",
5669 ipa_drv_res->apply_rg10_wa
5670 ? "Needed" : "Not needed");
5671
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005672 elem_num = of_property_count_elems_of_size(pdev->dev.of_node,
Ghanim Fodic823bc62017-10-21 17:29:53 +03005673 "qcom,mhi-event-ring-id-limits", sizeof(u32));
5674
5675 if (elem_num == 2) {
5676 if (of_property_read_u32_array(pdev->dev.of_node,
5677 "qcom,mhi-event-ring-id-limits", mhi_evid_limits, 2)) {
5678 IPAERR("failed to read mhi event ring id limits\n");
5679 return -EFAULT;
5680 }
5681 if (mhi_evid_limits[0] > mhi_evid_limits[1]) {
5682 IPAERR("mhi event ring id low limit > high limit\n");
5683 return -EFAULT;
5684 }
5685 ipa_drv_res->mhi_evid_limits[0] = mhi_evid_limits[0];
5686 ipa_drv_res->mhi_evid_limits[1] = mhi_evid_limits[1];
5687 IPADBG(": mhi-event-ring-id-limits start=%u end=%u\n",
5688 mhi_evid_limits[0], mhi_evid_limits[1]);
5689 } else {
5690 if (elem_num > 0) {
5691 IPAERR("Invalid mhi event ring id limits number %d\n",
5692 elem_num);
5693 return -EINVAL;
5694 }
5695 IPADBG("use default mhi evt ring id limits start=%u end=%u\n",
5696 ipa_drv_res->mhi_evid_limits[0],
5697 ipa_drv_res->mhi_evid_limits[1]);
5698 }
5699
5700 elem_num = of_property_count_elems_of_size(pdev->dev.of_node,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005701 "qcom,ipa-tz-unlock-reg", sizeof(u32));
5702
5703 if (elem_num > 0 && elem_num % 2 == 0) {
5704 ipa_drv_res->ipa_tz_unlock_reg_num = elem_num / 2;
5705
5706 ipa_tz_unlock_reg = kcalloc(elem_num, sizeof(u32), GFP_KERNEL);
5707 if (ipa_tz_unlock_reg == NULL)
5708 return -ENOMEM;
5709
5710 ipa_drv_res->ipa_tz_unlock_reg = kcalloc(
5711 ipa_drv_res->ipa_tz_unlock_reg_num,
5712 sizeof(*ipa_drv_res->ipa_tz_unlock_reg),
5713 GFP_KERNEL);
5714 if (ipa_drv_res->ipa_tz_unlock_reg == NULL) {
5715 kfree(ipa_tz_unlock_reg);
5716 return -ENOMEM;
5717 }
5718
5719 if (of_property_read_u32_array(pdev->dev.of_node,
5720 "qcom,ipa-tz-unlock-reg", ipa_tz_unlock_reg,
5721 elem_num)) {
5722 IPAERR("failed to read register addresses\n");
5723 kfree(ipa_tz_unlock_reg);
5724 kfree(ipa_drv_res->ipa_tz_unlock_reg);
5725 return -EFAULT;
5726 }
5727
5728 pos = 0;
5729 for (i = 0; i < ipa_drv_res->ipa_tz_unlock_reg_num; i++) {
5730 ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr =
5731 ipa_tz_unlock_reg[pos++];
5732 ipa_drv_res->ipa_tz_unlock_reg[i].size =
5733 ipa_tz_unlock_reg[pos++];
Skylar Chang48afa052017-10-25 09:32:57 -07005734 IPADBG("tz unlock reg %d: addr 0x%pa size %llu\n", i,
Gidon Studinski3021a6f2016-11-10 12:48:48 +02005735 &ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr,
5736 ipa_drv_res->ipa_tz_unlock_reg[i].size);
5737 }
5738 kfree(ipa_tz_unlock_reg);
5739 }
Michael Adisumarta3e350812017-09-18 14:54:36 -07005740
5741 /* get IPA PM related information */
5742 result = get_ipa_dts_pm_info(pdev, ipa_drv_res);
5743 if (result) {
5744 IPAERR("failed to get pm info from dts %d\n", result);
5745 return result;
5746 }
5747
Amir Levy9659e592016-10-27 18:08:27 +03005748 return 0;
5749}
5750
5751static int ipa_smmu_wlan_cb_probe(struct device *dev)
5752{
5753 struct ipa_smmu_cb_ctx *cb = ipa3_get_wlan_smmu_ctx();
Amir Levy9659e592016-10-27 18:08:27 +03005754 int atomic_ctx = 1;
5755 int fast = 1;
5756 int bypass = 1;
5757 int ret;
5758 u32 add_map_size;
5759 const u32 *add_map;
5760 int i;
5761
5762 IPADBG("sub pdev=%p\n", dev);
5763
5764 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02005765 cb->iommu = iommu_domain_alloc(dev->bus);
Amir Levy9659e592016-10-27 18:08:27 +03005766 if (!cb->iommu) {
5767 IPAERR("could not alloc iommu domain\n");
5768 /* assume this failure is because iommu driver is not ready */
5769 return -EPROBE_DEFER;
5770 }
5771 cb->valid = true;
5772
Michael Adisumarta93e97522017-10-06 15:49:46 -07005773 if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass")) {
5774 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = true;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005775 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN] = true;
5776
Amir Levy9659e592016-10-27 18:08:27 +03005777 if (iommu_domain_set_attr(cb->iommu,
5778 DOMAIN_ATTR_S1_BYPASS,
5779 &bypass)) {
5780 IPAERR("couldn't set bypass\n");
5781 cb->valid = false;
5782 return -EIO;
5783 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07005784 IPADBG("WLAN SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03005785 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07005786 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = false;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005787 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN] = false;
5788
Amir Levy9659e592016-10-27 18:08:27 +03005789 if (iommu_domain_set_attr(cb->iommu,
5790 DOMAIN_ATTR_ATOMIC,
5791 &atomic_ctx)) {
5792 IPAERR("couldn't disable coherent HTW\n");
5793 cb->valid = false;
5794 return -EIO;
5795 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07005796 IPADBG(" WLAN SMMU ATTR ATOMIC\n");
Amir Levy9659e592016-10-27 18:08:27 +03005797
5798 if (smmu_info.fast_map) {
5799 if (iommu_domain_set_attr(cb->iommu,
5800 DOMAIN_ATTR_FAST,
5801 &fast)) {
5802 IPAERR("couldn't set fast map\n");
5803 cb->valid = false;
5804 return -EIO;
5805 }
5806 IPADBG("SMMU fast map set\n");
5807 }
5808 }
5809
Michael Adisumarta93e97522017-10-06 15:49:46 -07005810 pr_info("IPA smmu_info.s1_bypass_arr[WLAN]=%d smmu_info.fast_map=%d\n",
5811 smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN], smmu_info.fast_map);
5812
Amir Levy9659e592016-10-27 18:08:27 +03005813 ret = iommu_attach_device(cb->iommu, dev);
5814 if (ret) {
5815 IPAERR("could not attach device ret=%d\n", ret);
5816 cb->valid = false;
5817 return ret;
5818 }
5819 /* MAP ipa-uc ram */
5820 add_map = of_get_property(dev->of_node,
5821 "qcom,additional-mapping", &add_map_size);
5822 if (add_map) {
5823 /* mapping size is an array of 3-tuple of u32 */
5824 if (add_map_size % (3 * sizeof(u32))) {
5825 IPAERR("wrong additional mapping format\n");
5826 cb->valid = false;
5827 return -EFAULT;
5828 }
5829
5830 /* iterate of each entry of the additional mapping array */
5831 for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
5832 u32 iova = be32_to_cpu(add_map[i]);
5833 u32 pa = be32_to_cpu(add_map[i + 1]);
5834 u32 size = be32_to_cpu(add_map[i + 2]);
5835 unsigned long iova_p;
5836 phys_addr_t pa_p;
5837 u32 size_p;
5838
5839 IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
5840 iova_p, pa_p, size_p);
5841 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
5842 iova_p, &pa_p, size_p);
5843 ipa3_iommu_map(cb->iommu,
5844 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02005845 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03005846 }
5847 }
5848 return 0;
5849}
5850
5851static int ipa_smmu_uc_cb_probe(struct device *dev)
5852{
5853 struct ipa_smmu_cb_ctx *cb = ipa3_get_uc_smmu_ctx();
Amir Levy9659e592016-10-27 18:08:27 +03005854 int atomic_ctx = 1;
5855 int bypass = 1;
5856 int fast = 1;
5857 int ret;
5858 u32 iova_ap_mapping[2];
5859
5860 IPADBG("UC CB PROBE sub pdev=%p\n", dev);
5861
5862 ret = of_property_read_u32_array(dev->of_node, "qcom,iova-mapping",
5863 iova_ap_mapping, 2);
5864 if (ret) {
5865 IPAERR("Fail to read UC start/size iova addresses\n");
5866 return ret;
5867 }
5868 cb->va_start = iova_ap_mapping[0];
5869 cb->va_size = iova_ap_mapping[1];
5870 cb->va_end = cb->va_start + cb->va_size;
5871 IPADBG("UC va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
5872
5873 if (smmu_info.use_64_bit_dma_mask) {
5874 if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
5875 dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
5876 IPAERR("DMA set 64bit mask failed\n");
5877 return -EOPNOTSUPP;
5878 }
5879 } else {
5880 if (dma_set_mask(dev, DMA_BIT_MASK(32)) ||
5881 dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
5882 IPAERR("DMA set 32bit mask failed\n");
5883 return -EOPNOTSUPP;
5884 }
5885 }
5886 IPADBG("UC CB PROBE=%p create IOMMU mapping\n", dev);
5887
5888 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02005889 cb->mapping = arm_iommu_create_mapping(dev->bus,
Amir Levy9659e592016-10-27 18:08:27 +03005890 cb->va_start, cb->va_size);
5891 if (IS_ERR_OR_NULL(cb->mapping)) {
5892 IPADBG("Fail to create mapping\n");
5893 /* assume this failure is because iommu driver is not ready */
5894 return -EPROBE_DEFER;
5895 }
5896 IPADBG("SMMU mapping created\n");
5897 cb->valid = true;
5898
Amir Levy9659e592016-10-27 18:08:27 +03005899 IPADBG("UC CB PROBE sub pdev=%p set attribute\n", dev);
Michael Adisumarta93e97522017-10-06 15:49:46 -07005900
5901 if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass")) {
5902 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC] = true;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005903 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = true;
5904
Amir Levy9659e592016-10-27 18:08:27 +03005905 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07005906 DOMAIN_ATTR_S1_BYPASS,
5907 &bypass)) {
Amir Levy9659e592016-10-27 18:08:27 +03005908 IPAERR("couldn't set bypass\n");
5909 arm_iommu_release_mapping(cb->mapping);
5910 cb->valid = false;
5911 return -EIO;
5912 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07005913 IPADBG("UC SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03005914 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07005915 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC] = false;
Michael Adisumarta972e33e2017-10-20 15:24:27 -07005916 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = false;
5917
Amir Levy9659e592016-10-27 18:08:27 +03005918 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07005919 DOMAIN_ATTR_ATOMIC,
5920 &atomic_ctx)) {
Amir Levy9659e592016-10-27 18:08:27 +03005921 IPAERR("couldn't set domain as atomic\n");
5922 arm_iommu_release_mapping(cb->mapping);
5923 cb->valid = false;
5924 return -EIO;
5925 }
5926 IPADBG("SMMU atomic set\n");
5927
5928 if (smmu_info.fast_map) {
5929 if (iommu_domain_set_attr(cb->mapping->domain,
Michael Adisumarta93e97522017-10-06 15:49:46 -07005930 DOMAIN_ATTR_FAST,
5931 &fast)) {
Amir Levy9659e592016-10-27 18:08:27 +03005932 IPAERR("couldn't set fast map\n");
5933 arm_iommu_release_mapping(cb->mapping);
5934 cb->valid = false;
5935 return -EIO;
5936 }
5937 IPADBG("SMMU fast map set\n");
5938 }
5939 }
5940
Michael Adisumarta93e97522017-10-06 15:49:46 -07005941 pr_info("IPA smmu_info.s1_bypass_arr[UC]=%d smmu_info.fast_map=%d\n",
5942 smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC], smmu_info.fast_map);
5943
Amir Levy9659e592016-10-27 18:08:27 +03005944 IPADBG("UC CB PROBE sub pdev=%p attaching IOMMU device\n", dev);
5945 ret = arm_iommu_attach_device(cb->dev, cb->mapping);
5946 if (ret) {
5947 IPAERR("could not attach device ret=%d\n", ret);
5948 arm_iommu_release_mapping(cb->mapping);
5949 cb->valid = false;
5950 return ret;
5951 }
5952
5953 cb->next_addr = cb->va_end;
5954 ipa3_ctx->uc_pdev = dev;
5955
5956 return 0;
5957}
5958
5959static int ipa_smmu_ap_cb_probe(struct device *dev)
5960{
5961 struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx();
5962 int result;
Amir Levy9659e592016-10-27 18:08:27 +03005963 int atomic_ctx = 1;
5964 int fast = 1;
5965 int bypass = 1;
5966 u32 iova_ap_mapping[2];
5967 u32 add_map_size;
5968 const u32 *add_map;
5969 void *smem_addr;
5970 int i;
5971
5972 IPADBG("AP CB probe: sub pdev=%p\n", dev);
5973
5974 result = of_property_read_u32_array(dev->of_node, "qcom,iova-mapping",
5975 iova_ap_mapping, 2);
5976 if (result) {
5977 IPAERR("Fail to read AP start/size iova addresses\n");
5978 return result;
5979 }
5980 cb->va_start = iova_ap_mapping[0];
5981 cb->va_size = iova_ap_mapping[1];
5982 cb->va_end = cb->va_start + cb->va_size;
5983 IPADBG("AP va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
5984
5985 if (smmu_info.use_64_bit_dma_mask) {
5986 if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
5987 dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
5988 IPAERR("DMA set 64bit mask failed\n");
5989 return -EOPNOTSUPP;
5990 }
5991 } else {
5992 if (dma_set_mask(dev, DMA_BIT_MASK(32)) ||
5993 dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
5994 IPAERR("DMA set 32bit mask failed\n");
5995 return -EOPNOTSUPP;
5996 }
5997 }
5998
5999 cb->dev = dev;
Amir Levyf5625342016-12-25 10:21:02 +02006000 cb->mapping = arm_iommu_create_mapping(dev->bus,
Amir Levy9659e592016-10-27 18:08:27 +03006001 cb->va_start, cb->va_size);
6002 if (IS_ERR_OR_NULL(cb->mapping)) {
6003 IPADBG("Fail to create mapping\n");
6004 /* assume this failure is because iommu driver is not ready */
6005 return -EPROBE_DEFER;
6006 }
6007 IPADBG("SMMU mapping created\n");
6008 cb->valid = true;
6009
Michael Adisumarta93e97522017-10-06 15:49:46 -07006010 if (of_property_read_bool(dev->of_node,
6011 "qcom,smmu-s1-bypass")) {
6012 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP] = true;
Amir Levy9659e592016-10-27 18:08:27 +03006013 if (iommu_domain_set_attr(cb->mapping->domain,
6014 DOMAIN_ATTR_S1_BYPASS,
6015 &bypass)) {
6016 IPAERR("couldn't set bypass\n");
6017 arm_iommu_release_mapping(cb->mapping);
6018 cb->valid = false;
6019 return -EIO;
6020 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006021 IPADBG("AP/USB SMMU S1 BYPASS\n");
Amir Levy9659e592016-10-27 18:08:27 +03006022 } else {
Michael Adisumarta93e97522017-10-06 15:49:46 -07006023 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP] = false;
Amir Levy9659e592016-10-27 18:08:27 +03006024 if (iommu_domain_set_attr(cb->mapping->domain,
6025 DOMAIN_ATTR_ATOMIC,
6026 &atomic_ctx)) {
6027 IPAERR("couldn't set domain as atomic\n");
6028 arm_iommu_release_mapping(cb->mapping);
6029 cb->valid = false;
6030 return -EIO;
6031 }
Michael Adisumarta93e97522017-10-06 15:49:46 -07006032 IPADBG("AP/USB SMMU atomic set\n");
Amir Levy9659e592016-10-27 18:08:27 +03006033
6034 if (iommu_domain_set_attr(cb->mapping->domain,
6035 DOMAIN_ATTR_FAST,
6036 &fast)) {
6037 IPAERR("couldn't set fast map\n");
6038 arm_iommu_release_mapping(cb->mapping);
6039 cb->valid = false;
6040 return -EIO;
6041 }
6042 IPADBG("SMMU fast map set\n");
6043 }
6044
Michael Adisumarta93e97522017-10-06 15:49:46 -07006045 pr_info("IPA smmu_info.s1_bypass_arr[AP]=%d smmu_info.fast_map=%d\n",
6046 smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP], smmu_info.fast_map);
6047
Amir Levy9659e592016-10-27 18:08:27 +03006048 result = arm_iommu_attach_device(cb->dev, cb->mapping);
6049 if (result) {
6050 IPAERR("couldn't attach to IOMMU ret=%d\n", result);
6051 cb->valid = false;
6052 return result;
6053 }
6054
6055 add_map = of_get_property(dev->of_node,
6056 "qcom,additional-mapping", &add_map_size);
6057 if (add_map) {
6058 /* mapping size is an array of 3-tuple of u32 */
6059 if (add_map_size % (3 * sizeof(u32))) {
6060 IPAERR("wrong additional mapping format\n");
6061 cb->valid = false;
6062 return -EFAULT;
6063 }
6064
6065 /* iterate of each entry of the additional mapping array */
6066 for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
6067 u32 iova = be32_to_cpu(add_map[i]);
6068 u32 pa = be32_to_cpu(add_map[i + 1]);
6069 u32 size = be32_to_cpu(add_map[i + 2]);
6070 unsigned long iova_p;
6071 phys_addr_t pa_p;
6072 u32 size_p;
6073
6074 IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
6075 iova_p, pa_p, size_p);
6076 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
6077 iova_p, &pa_p, size_p);
6078 ipa3_iommu_map(cb->mapping->domain,
6079 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02006080 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03006081 }
6082 }
6083
6084 /* map SMEM memory for IPA table accesses */
6085 smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
6086 SMEM_MODEM, 0);
6087 if (smem_addr) {
6088 phys_addr_t iova = smem_virt_to_phys(smem_addr);
6089 phys_addr_t pa = iova;
6090 unsigned long iova_p;
6091 phys_addr_t pa_p;
6092 u32 size_p;
6093
6094 IPA_SMMU_ROUND_TO_PAGE(iova, pa, IPA_SMEM_SIZE,
6095 iova_p, pa_p, size_p);
6096 IPADBG("mapping 0x%lx to 0x%pa size %d\n",
6097 iova_p, &pa_p, size_p);
6098 ipa3_iommu_map(cb->mapping->domain,
6099 iova_p, pa_p, size_p,
Amir Levyf5625342016-12-25 10:21:02 +02006100 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
Amir Levy9659e592016-10-27 18:08:27 +03006101 }
6102
6103
6104 smmu_info.present = true;
6105
6106 if (!ipa3_bus_scale_table)
6107 ipa3_bus_scale_table = msm_bus_cl_get_pdata(ipa3_pdev);
6108
6109 /* Proceed to real initialization */
6110 result = ipa3_pre_init(&ipa3_res, dev);
6111 if (result) {
6112 IPAERR("ipa_init failed\n");
6113 arm_iommu_detach_device(cb->dev);
6114 arm_iommu_release_mapping(cb->mapping);
6115 cb->valid = false;
6116 return result;
6117 }
6118
6119 return result;
6120}
6121
6122static irqreturn_t ipa3_smp2p_modem_clk_query_isr(int irq, void *ctxt)
6123{
6124 ipa3_freeze_clock_vote_and_notify_modem();
6125
6126 return IRQ_HANDLED;
6127}
6128
6129static int ipa3_smp2p_probe(struct device *dev)
6130{
6131 struct device_node *node = dev->of_node;
6132 int res;
6133
Mohammed Javid7de12702017-07-21 15:22:58 +05306134 if (ipa3_ctx == NULL) {
6135 IPAERR("ipa3_ctx was not initialized\n");
6136 return -ENXIO;
6137 }
Amir Levy9659e592016-10-27 18:08:27 +03006138 IPADBG("node->name=%s\n", node->name);
6139 if (strcmp("qcom,smp2pgpio_map_ipa_1_out", node->name) == 0) {
6140 res = of_get_gpio(node, 0);
6141 if (res < 0) {
6142 IPADBG("of_get_gpio returned %d\n", res);
6143 return res;
6144 }
6145
6146 ipa3_ctx->smp2p_info.out_base_id = res;
6147 IPADBG("smp2p out_base_id=%d\n",
6148 ipa3_ctx->smp2p_info.out_base_id);
6149 } else if (strcmp("qcom,smp2pgpio_map_ipa_1_in", node->name) == 0) {
6150 int irq;
6151
6152 res = of_get_gpio(node, 0);
6153 if (res < 0) {
6154 IPADBG("of_get_gpio returned %d\n", res);
6155 return res;
6156 }
6157
6158 ipa3_ctx->smp2p_info.in_base_id = res;
6159 IPADBG("smp2p in_base_id=%d\n",
6160 ipa3_ctx->smp2p_info.in_base_id);
6161
6162 /* register for modem clk query */
6163 irq = gpio_to_irq(ipa3_ctx->smp2p_info.in_base_id +
6164 IPA_GPIO_IN_QUERY_CLK_IDX);
6165 if (irq < 0) {
6166 IPAERR("gpio_to_irq failed %d\n", irq);
6167 return -ENODEV;
6168 }
6169 IPADBG("smp2p irq#=%d\n", irq);
6170 res = request_irq(irq,
6171 (irq_handler_t)ipa3_smp2p_modem_clk_query_isr,
6172 IRQF_TRIGGER_RISING, "ipa_smp2p_clk_vote", dev);
6173 if (res) {
6174 IPAERR("fail to register smp2p irq=%d\n", irq);
6175 return -ENODEV;
6176 }
6177 res = enable_irq_wake(ipa3_ctx->smp2p_info.in_base_id +
6178 IPA_GPIO_IN_QUERY_CLK_IDX);
6179 if (res)
6180 IPAERR("failed to enable irq wake\n");
6181 }
6182
6183 return 0;
6184}
6185
6186int ipa3_plat_drv_probe(struct platform_device *pdev_p,
6187 struct ipa_api_controller *api_ctrl,
6188 const struct of_device_id *pdrv_match)
6189{
6190 int result;
6191 struct device *dev = &pdev_p->dev;
6192
6193 IPADBG("IPA driver probing started\n");
6194 IPADBG("dev->of_node->name = %s\n", dev->of_node->name);
6195
6196 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-ap-cb"))
6197 return ipa_smmu_ap_cb_probe(dev);
6198
6199 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-wlan-cb"))
6200 return ipa_smmu_wlan_cb_probe(dev);
6201
6202 if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-uc-cb"))
6203 return ipa_smmu_uc_cb_probe(dev);
6204
6205 if (of_device_is_compatible(dev->of_node,
6206 "qcom,smp2pgpio-map-ipa-1-in"))
6207 return ipa3_smp2p_probe(dev);
6208
6209 if (of_device_is_compatible(dev->of_node,
6210 "qcom,smp2pgpio-map-ipa-1-out"))
6211 return ipa3_smp2p_probe(dev);
6212
6213 master_dev = dev;
6214 if (!ipa3_pdev)
6215 ipa3_pdev = pdev_p;
6216
6217 result = get_ipa_dts_configuration(pdev_p, &ipa3_res);
6218 if (result) {
6219 IPAERR("IPA dts parsing failed\n");
6220 return result;
6221 }
6222
6223 result = ipa3_bind_api_controller(ipa3_res.ipa_hw_type, api_ctrl);
6224 if (result) {
6225 IPAERR("IPA API binding failed\n");
6226 return result;
6227 }
6228
Amir Levy9659e592016-10-27 18:08:27 +03006229 if (of_property_read_bool(pdev_p->dev.of_node, "qcom,arm-smmu")) {
6230 if (of_property_read_bool(pdev_p->dev.of_node,
Amir Levy9659e592016-10-27 18:08:27 +03006231 "qcom,smmu-fast-map"))
6232 smmu_info.fast_map = true;
6233 if (of_property_read_bool(pdev_p->dev.of_node,
6234 "qcom,use-64-bit-dma-mask"))
6235 smmu_info.use_64_bit_dma_mask = true;
6236 smmu_info.arm_smmu = true;
Amir Levy9659e592016-10-27 18:08:27 +03006237 } else if (of_property_read_bool(pdev_p->dev.of_node,
6238 "qcom,msm-smmu")) {
6239 IPAERR("Legacy IOMMU not supported\n");
6240 result = -EOPNOTSUPP;
6241 } else {
6242 if (of_property_read_bool(pdev_p->dev.of_node,
6243 "qcom,use-64-bit-dma-mask")) {
6244 if (dma_set_mask(&pdev_p->dev, DMA_BIT_MASK(64)) ||
6245 dma_set_coherent_mask(&pdev_p->dev,
6246 DMA_BIT_MASK(64))) {
6247 IPAERR("DMA set 64bit mask failed\n");
6248 return -EOPNOTSUPP;
6249 }
6250 } else {
6251 if (dma_set_mask(&pdev_p->dev, DMA_BIT_MASK(32)) ||
6252 dma_set_coherent_mask(&pdev_p->dev,
6253 DMA_BIT_MASK(32))) {
6254 IPAERR("DMA set 32bit mask failed\n");
6255 return -EOPNOTSUPP;
6256 }
6257 }
6258
6259 if (!ipa3_bus_scale_table)
6260 ipa3_bus_scale_table = msm_bus_cl_get_pdata(pdev_p);
6261 /* Proceed to real initialization */
6262 result = ipa3_pre_init(&ipa3_res, dev);
6263 if (result) {
6264 IPAERR("ipa3_init failed\n");
6265 return result;
6266 }
6267 }
6268
Ghanim Fodi115bf8a2017-04-21 01:36:06 -07006269 result = of_platform_populate(pdev_p->dev.of_node,
6270 pdrv_match, NULL, &pdev_p->dev);
6271 if (result) {
6272 IPAERR("failed to populate platform\n");
6273 return result;
6274 }
6275
Amir Levy9659e592016-10-27 18:08:27 +03006276 return result;
6277}
6278
6279/**
6280 * ipa3_ap_suspend() - suspend callback for runtime_pm
6281 * @dev: pointer to device
6282 *
6283 * This callback will be invoked by the runtime_pm framework when an AP suspend
6284 * operation is invoked, usually by pressing a suspend button.
6285 *
6286 * Returns -EAGAIN to runtime_pm framework in case IPA is in use by AP.
6287 * This will postpone the suspend operation until IPA is no longer used by AP.
6288*/
6289int ipa3_ap_suspend(struct device *dev)
6290{
6291 int i;
6292
6293 IPADBG("Enter...\n");
6294
6295 /* In case there is a tx/rx handler in polling mode fail to suspend */
6296 for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
6297 if (ipa3_ctx->ep[i].sys &&
6298 atomic_read(&ipa3_ctx->ep[i].sys->curr_polling_state)) {
6299 IPAERR("EP %d is in polling state, do not suspend\n",
6300 i);
6301 return -EAGAIN;
6302 }
6303 }
6304
Michael Adisumarta3e350812017-09-18 14:54:36 -07006305 if (ipa3_ctx->use_ipa_pm) {
6306 ipa_pm_deactivate_all_deferred();
6307 } else {
6308 /*
6309 * Release transport IPA resource without waiting
6310 * for inactivity timer
6311 */
6312 atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
6313 ipa3_transport_release_resource(NULL);
6314 }
Amir Levy9659e592016-10-27 18:08:27 +03006315 IPADBG("Exit\n");
6316
6317 return 0;
6318}
6319
6320/**
6321* ipa3_ap_resume() - resume callback for runtime_pm
6322* @dev: pointer to device
6323*
6324* This callback will be invoked by the runtime_pm framework when an AP resume
6325* operation is invoked.
6326*
6327* Always returns 0 since resume should always succeed.
6328*/
6329int ipa3_ap_resume(struct device *dev)
6330{
6331 return 0;
6332}
6333
6334struct ipa3_context *ipa3_get_ctx(void)
6335{
6336 return ipa3_ctx;
6337}
6338
Amir Levy9659e592016-10-27 18:08:27 +03006339static void ipa_gsi_notify_cb(struct gsi_per_notify *notify)
6340{
6341 switch (notify->evt_id) {
6342 case GSI_PER_EVT_GLOB_ERROR:
6343 IPAERR("Got GSI_PER_EVT_GLOB_ERROR\n");
6344 IPAERR("Err_desc = 0x%04x\n", notify->data.err_desc);
6345 break;
6346 case GSI_PER_EVT_GLOB_GP1:
6347 IPAERR("Got GSI_PER_EVT_GLOB_GP1\n");
6348 BUG();
6349 break;
6350 case GSI_PER_EVT_GLOB_GP2:
6351 IPAERR("Got GSI_PER_EVT_GLOB_GP2\n");
6352 BUG();
6353 break;
6354 case GSI_PER_EVT_GLOB_GP3:
6355 IPAERR("Got GSI_PER_EVT_GLOB_GP3\n");
6356 BUG();
6357 break;
6358 case GSI_PER_EVT_GENERAL_BREAK_POINT:
6359 IPAERR("Got GSI_PER_EVT_GENERAL_BREAK_POINT\n");
6360 break;
6361 case GSI_PER_EVT_GENERAL_BUS_ERROR:
6362 IPAERR("Got GSI_PER_EVT_GENERAL_BUS_ERROR\n");
6363 BUG();
6364 break;
6365 case GSI_PER_EVT_GENERAL_CMD_FIFO_OVERFLOW:
6366 IPAERR("Got GSI_PER_EVT_GENERAL_CMD_FIFO_OVERFLOW\n");
6367 BUG();
6368 break;
6369 case GSI_PER_EVT_GENERAL_MCS_STACK_OVERFLOW:
6370 IPAERR("Got GSI_PER_EVT_GENERAL_MCS_STACK_OVERFLOW\n");
6371 BUG();
6372 break;
6373 default:
6374 IPAERR("Received unexpected evt: %d\n",
6375 notify->evt_id);
6376 BUG();
6377 }
6378}
6379
6380int ipa3_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data)
6381{
6382 struct ipa3_ready_cb_info *cb_info = NULL;
6383
6384 /* check ipa3_ctx existed or not */
6385 if (!ipa3_ctx) {
6386 IPADBG("IPA driver haven't initialized\n");
6387 return -ENXIO;
6388 }
6389 mutex_lock(&ipa3_ctx->lock);
6390 if (ipa3_ctx->ipa_initialization_complete) {
6391 mutex_unlock(&ipa3_ctx->lock);
6392 IPADBG("IPA driver finished initialization already\n");
6393 return -EEXIST;
6394 }
6395
6396 cb_info = kmalloc(sizeof(struct ipa3_ready_cb_info), GFP_KERNEL);
6397 if (!cb_info) {
6398 mutex_unlock(&ipa3_ctx->lock);
6399 return -ENOMEM;
6400 }
6401
6402 cb_info->ready_cb = ipa_ready_cb;
6403 cb_info->user_data = user_data;
6404
6405 list_add_tail(&cb_info->link, &ipa3_ctx->ipa_ready_cb_list);
6406 mutex_unlock(&ipa3_ctx->lock);
6407
6408 return 0;
6409}
6410
6411int ipa3_iommu_map(struct iommu_domain *domain,
6412 unsigned long iova, phys_addr_t paddr, size_t size, int prot)
6413{
6414 struct ipa_smmu_cb_ctx *ap_cb = ipa3_get_smmu_ctx();
6415 struct ipa_smmu_cb_ctx *uc_cb = ipa3_get_uc_smmu_ctx();
6416
6417 IPADBG("domain =0x%p iova 0x%lx\n", domain, iova);
6418 IPADBG("paddr =0x%pa size 0x%x\n", &paddr, (u32)size);
6419
6420 /* make sure no overlapping */
6421 if (domain == ipa3_get_smmu_domain()) {
6422 if (iova >= ap_cb->va_start && iova < ap_cb->va_end) {
6423 IPAERR("iommu AP overlap addr 0x%lx\n", iova);
6424 ipa_assert();
6425 return -EFAULT;
6426 }
6427 } else if (domain == ipa3_get_wlan_smmu_domain()) {
6428 /* wlan is one time map */
6429 } else if (domain == ipa3_get_uc_smmu_domain()) {
6430 if (iova >= uc_cb->va_start && iova < uc_cb->va_end) {
6431 IPAERR("iommu uC overlap addr 0x%lx\n", iova);
6432 ipa_assert();
6433 return -EFAULT;
6434 }
6435 } else {
6436 IPAERR("Unexpected domain 0x%p\n", domain);
6437 ipa_assert();
6438 return -EFAULT;
6439 }
6440
6441 return iommu_map(domain, iova, paddr, size, prot);
6442}
6443
Michael Adisumartad04e6d62017-11-09 17:46:35 -08006444/**
6445 * ipa3_get_smmu_params()- Return the ipa3 smmu related params.
6446 */
6447int ipa3_get_smmu_params(struct ipa_smmu_in_params *in,
6448 struct ipa_smmu_out_params *out)
6449{
6450 bool is_smmu_enable = 0;
6451
6452 if (out == NULL || in == NULL) {
6453 IPAERR("bad parms for Client SMMU out params\n");
6454 return -EINVAL;
6455 }
6456
6457 if (!ipa3_ctx) {
6458 IPAERR("IPA not yet initialized\n");
6459 return -EINVAL;
6460 }
6461
6462 switch (in->smmu_client) {
6463 case IPA_SMMU_WLAN_CLIENT:
6464 is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] |
6465 ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN]);
6466 break;
6467 default:
6468 is_smmu_enable = 0;
6469 IPAERR("Trying to get illegal clients SMMU status");
6470 return -EINVAL;
6471 }
6472
6473 out->smmu_enable = is_smmu_enable;
6474
6475 return 0;
6476}
6477
Amir Levy9659e592016-10-27 18:08:27 +03006478MODULE_LICENSE("GPL v2");
6479MODULE_DESCRIPTION("IPA HW device driver");