blob: 736c0fb1b7f04f92f302eb6ba966b053e9913935 [file] [log] [blame]
Ghanim Fodi5fd0c952018-01-31 14:49:37 +02001/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
Amir Levy9659e592016-10-27 18:08:27 +03002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/bitops.h>
14#include <linux/idr.h>
15#include "ipa_i.h"
16#include "ipahal/ipahal.h"
17#include "ipahal/ipahal_fltrt.h"
18
19#define IPA_RT_INDEX_BITMAP_SIZE (32)
20#define IPA_RT_STATUS_OF_ADD_FAILED (-1)
21#define IPA_RT_STATUS_OF_DEL_FAILED (-1)
22#define IPA_RT_STATUS_OF_MDFY_FAILED (-1)
23
Amir Levy479cfdd2017-10-26 12:23:14 +030024#define IPA_RT_MAX_NUM_OF_COMMIT_TABLES_CMD_DESC 5
25
Amir Levy9659e592016-10-27 18:08:27 +030026#define IPA_RT_GET_RULE_TYPE(__entry) \
27 ( \
28 ((__entry)->rule.hashable) ? \
29 (IPA_RULE_HASHABLE) : (IPA_RULE_NON_HASHABLE) \
30 )
31
32/**
33 * ipa_generate_rt_hw_rule() - Generated the RT H/W single rule
34 * This func will do the preparation core driver work and then calls
35 * the HAL layer for the real work.
36 * @ip: the ip address family type
37 * @entry: routing entry
38 * @buf: output buffer, buf == NULL means
39 * caller wants to know the size of the rule as seen
40 * by HW so they did not pass a valid buffer, we will use a
41 * scratch buffer instead.
42 * With this scheme we are going to
43 * generate the rule twice, once to know size using scratch
44 * buffer and second to write the rule to the actual caller
45 * supplied buffer which is of required size
46 *
47 * Returns: 0 on success, negative on failure
48 *
49 * caller needs to hold any needed locks to ensure integrity
50 */
51static int ipa_generate_rt_hw_rule(enum ipa_ip_type ip,
52 struct ipa3_rt_entry *entry, u8 *buf)
53{
54 struct ipahal_rt_rule_gen_params gen_params;
Mohammed Javid6f6eadb2018-02-20 16:01:26 +053055 struct ipa3_hdr_entry *hdr_entry;
56 struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
Amir Levy9659e592016-10-27 18:08:27 +030057 int res = 0;
58
59 memset(&gen_params, 0, sizeof(gen_params));
60
61 gen_params.ipt = ip;
62 gen_params.dst_pipe_idx = ipa3_get_ep_mapping(entry->rule.dst);
63 if (gen_params.dst_pipe_idx == -1) {
Mohammed Javida4252d82017-10-13 13:51:21 +053064 IPAERR_RL("Wrong destination pipe specified in RT rule\n");
65 WARN_ON_RATELIMIT_IPA(1);
Amir Levy9659e592016-10-27 18:08:27 +030066 return -EPERM;
67 }
68 if (!IPA_CLIENT_IS_CONS(entry->rule.dst)) {
Mohammed Javida4252d82017-10-13 13:51:21 +053069 IPAERR_RL("No RT rule on IPA_client_producer pipe.\n");
70 IPAERR_RL("pipe_idx: %d dst_pipe: %d\n",
Amir Levy9659e592016-10-27 18:08:27 +030071 gen_params.dst_pipe_idx, entry->rule.dst);
Mohammed Javida4252d82017-10-13 13:51:21 +053072 WARN_ON_RATELIMIT_IPA(1);
Amir Levy9659e592016-10-27 18:08:27 +030073 return -EPERM;
74 }
75
Mohammed Javid6f6eadb2018-02-20 16:01:26 +053076 /* Adding check to confirm still
77 * header entry present in header table or not
78 */
79
80 if (entry->hdr) {
81 hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
82 if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
83 IPAERR_RL("Header entry already deleted\n");
84 return -EPERM;
85 }
86 } else if (entry->proc_ctx) {
87 hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
88 if (!hdr_proc_entry ||
89 hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
90 IPAERR_RL("Proc header entry already deleted\n");
91 return -EPERM;
92 }
93 }
94
Amir Levy9659e592016-10-27 18:08:27 +030095 if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) {
96 struct ipa3_hdr_proc_ctx_entry *proc_ctx;
97
98 proc_ctx = (entry->proc_ctx) ? : entry->hdr->proc_ctx;
Mohammed Javid025d7bb2017-08-01 19:05:06 +053099 if ((proc_ctx == NULL) ||
100 (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) {
101 gen_params.hdr_type = IPAHAL_RT_RULE_HDR_NONE;
102 gen_params.hdr_ofst = 0;
103 } else {
104 gen_params.hdr_lcl = ipa3_ctx->hdr_proc_ctx_tbl_lcl;
105 gen_params.hdr_type = IPAHAL_RT_RULE_HDR_PROC_CTX;
106 gen_params.hdr_ofst = proc_ctx->offset_entry->offset +
107 ipa3_ctx->hdr_proc_ctx_tbl.start_offset;
108 }
109 } else if ((entry->hdr != NULL) &&
110 (entry->hdr->cookie == IPA_HDR_COOKIE)) {
Amir Levy9659e592016-10-27 18:08:27 +0300111 gen_params.hdr_lcl = ipa3_ctx->hdr_tbl_lcl;
112 gen_params.hdr_type = IPAHAL_RT_RULE_HDR_RAW;
113 gen_params.hdr_ofst = entry->hdr->offset_entry->offset;
114 } else {
115 gen_params.hdr_type = IPAHAL_RT_RULE_HDR_NONE;
116 gen_params.hdr_ofst = 0;
117 }
118
119 gen_params.priority = entry->prio;
120 gen_params.id = entry->rule_id;
121 gen_params.rule = (const struct ipa_rt_rule *)&entry->rule;
122
123 res = ipahal_rt_generate_hw_rule(&gen_params, &entry->hw_len, buf);
124 if (res)
125 IPAERR("failed to generate rt h/w rule\n");
126
127 return res;
128}
129
130/**
131 * ipa_translate_rt_tbl_to_hw_fmt() - translate the routing driver structures
132 * (rules and tables) to HW format and fill it in the given buffers
133 * @ip: the ip address family type
134 * @rlt: the type of the rules to translate (hashable or non-hashable)
135 * @base: the rules body buffer to be filled
136 * @hdr: the rules header (addresses/offsets) buffer to be filled
137 * @body_ofst: the offset of the rules body from the rules header at
138 * ipa sram (for local body usage)
139 * @apps_start_idx: the first rt table index of apps tables
140 *
141 * Returns: 0 on success, negative on failure
142 *
143 * caller needs to hold any needed locks to ensure integrity
144 *
145 */
146static int ipa_translate_rt_tbl_to_hw_fmt(enum ipa_ip_type ip,
147 enum ipa_rule_type rlt, u8 *base, u8 *hdr,
148 u32 body_ofst, u32 apps_start_idx)
149{
150 struct ipa3_rt_tbl_set *set;
151 struct ipa3_rt_tbl *tbl;
152 struct ipa_mem_buffer tbl_mem;
153 u8 *tbl_mem_buf;
154 struct ipa3_rt_entry *entry;
155 int res;
156 u64 offset;
157 u8 *body_i;
158
159 set = &ipa3_ctx->rt_tbl_set[ip];
160 body_i = base;
161 list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
162 if (tbl->sz[rlt] == 0)
163 continue;
164 if (tbl->in_sys[rlt]) {
165 /* only body (no header) */
166 tbl_mem.size = tbl->sz[rlt] -
167 ipahal_get_hw_tbl_hdr_width();
168 if (ipahal_fltrt_allocate_hw_sys_tbl(&tbl_mem)) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530169 IPAERR_RL("fail to alloc sys tbl of size %d\n",
Amir Levy9659e592016-10-27 18:08:27 +0300170 tbl_mem.size);
171 goto err;
172 }
173
174 if (ipahal_fltrt_write_addr_to_hdr(tbl_mem.phys_base,
175 hdr, tbl->idx - apps_start_idx, true)) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530176 IPAERR_RL("fail to wrt sys tbl addr to hdr\n");
Amir Levy9659e592016-10-27 18:08:27 +0300177 goto hdr_update_fail;
178 }
179
180 tbl_mem_buf = tbl_mem.base;
181
182 /* generate the rule-set */
183 list_for_each_entry(entry, &tbl->head_rt_rule_list,
184 link) {
185 if (IPA_RT_GET_RULE_TYPE(entry) != rlt)
186 continue;
187 res = ipa_generate_rt_hw_rule(ip, entry,
188 tbl_mem_buf);
189 if (res) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530190 IPAERR_RL("failed to gen HW RT rule\n");
Amir Levy9659e592016-10-27 18:08:27 +0300191 goto hdr_update_fail;
192 }
193 tbl_mem_buf += entry->hw_len;
194 }
195
196 if (tbl->curr_mem[rlt].phys_base) {
197 WARN_ON(tbl->prev_mem[rlt].phys_base);
198 tbl->prev_mem[rlt] = tbl->curr_mem[rlt];
199 }
200 tbl->curr_mem[rlt] = tbl_mem;
201 } else {
202 offset = body_i - base + body_ofst;
203
204 /* update the hdr at the right index */
205 if (ipahal_fltrt_write_addr_to_hdr(offset, hdr,
206 tbl->idx - apps_start_idx, true)) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530207 IPAERR_RL("fail to wrt lcl tbl ofst to hdr\n");
Amir Levy9659e592016-10-27 18:08:27 +0300208 goto hdr_update_fail;
209 }
210
211 /* generate the rule-set */
212 list_for_each_entry(entry, &tbl->head_rt_rule_list,
213 link) {
214 if (IPA_RT_GET_RULE_TYPE(entry) != rlt)
215 continue;
216 res = ipa_generate_rt_hw_rule(ip, entry,
217 body_i);
218 if (res) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530219 IPAERR_RL("failed to gen HW RT rule\n");
Amir Levy9659e592016-10-27 18:08:27 +0300220 goto err;
221 }
222 body_i += entry->hw_len;
223 }
224
225 /**
226 * advance body_i to next table alignment as local
227 * tables
228 * are order back-to-back
229 */
230 body_i += ipahal_get_lcl_tbl_addr_alignment();
231 body_i = (u8 *)((long)body_i &
232 ~ipahal_get_lcl_tbl_addr_alignment());
233 }
234 }
235
236 return 0;
237
238hdr_update_fail:
239 ipahal_free_dma_mem(&tbl_mem);
240err:
241 return -EPERM;
242}
243
244static void __ipa_reap_sys_rt_tbls(enum ipa_ip_type ip)
245{
246 struct ipa3_rt_tbl *tbl;
247 struct ipa3_rt_tbl *next;
248 struct ipa3_rt_tbl_set *set;
249 int i;
250
251 set = &ipa3_ctx->rt_tbl_set[ip];
252 list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
253 for (i = 0; i < IPA_RULE_TYPE_MAX; i++) {
254 if (tbl->prev_mem[i].phys_base) {
255 IPADBG_LOW(
256 "reaping sys rt tbl name=%s ip=%d rlt=%d\n",
257 tbl->name, ip, i);
258 ipahal_free_dma_mem(&tbl->prev_mem[i]);
259 memset(&tbl->prev_mem[i], 0,
260 sizeof(tbl->prev_mem[i]));
261 }
262 }
263 }
264
265 set = &ipa3_ctx->reap_rt_tbl_set[ip];
266 list_for_each_entry_safe(tbl, next, &set->head_rt_tbl_list, link) {
267 for (i = 0; i < IPA_RULE_TYPE_MAX; i++) {
268 WARN_ON(tbl->prev_mem[i].phys_base != 0);
269 if (tbl->curr_mem[i].phys_base) {
270 IPADBG_LOW(
271 "reaping sys rt tbl name=%s ip=%d rlt=%d\n",
272 tbl->name, ip, i);
273 ipahal_free_dma_mem(&tbl->curr_mem[i]);
274 }
275 }
276 list_del(&tbl->link);
277 kmem_cache_free(ipa3_ctx->rt_tbl_cache, tbl);
278 }
279}
280
281/**
282 * ipa_prep_rt_tbl_for_cmt() - preparing the rt table for commit
283 * assign priorities to the rules, calculate their sizes and calculate
284 * the overall table size
285 * @ip: the ip address family type
286 * @tbl: the rt tbl to be prepared
287 *
288 * Return: 0 on success, negative on failure
289 */
290static int ipa_prep_rt_tbl_for_cmt(enum ipa_ip_type ip,
291 struct ipa3_rt_tbl *tbl)
292{
293 struct ipa3_rt_entry *entry;
294 int prio_i;
295 int res;
296 int max_prio;
297 u32 hdr_width;
298
299 tbl->sz[IPA_RULE_HASHABLE] = 0;
300 tbl->sz[IPA_RULE_NON_HASHABLE] = 0;
301
302 max_prio = ipahal_get_rule_max_priority();
303
304 prio_i = max_prio;
305 list_for_each_entry(entry, &tbl->head_rt_rule_list, link) {
306
307 if (entry->rule.max_prio) {
308 entry->prio = max_prio;
309 } else {
310 if (ipahal_rule_decrease_priority(&prio_i)) {
311 IPAERR("cannot rule decrease priority - %d\n",
312 prio_i);
313 return -EPERM;
314 }
315 entry->prio = prio_i;
316 }
317
318 res = ipa_generate_rt_hw_rule(ip, entry, NULL);
319 if (res) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530320 IPAERR_RL("failed to calculate HW RT rule size\n");
Amir Levy9659e592016-10-27 18:08:27 +0300321 return -EPERM;
322 }
323
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200324 IPADBG_LOW("RT rule id (handle) %d hw_len %u priority %u\n",
Amir Levy9659e592016-10-27 18:08:27 +0300325 entry->id, entry->hw_len, entry->prio);
326
327 if (entry->rule.hashable)
328 tbl->sz[IPA_RULE_HASHABLE] += entry->hw_len;
329 else
330 tbl->sz[IPA_RULE_NON_HASHABLE] += entry->hw_len;
331 }
332
333 if ((tbl->sz[IPA_RULE_HASHABLE] +
334 tbl->sz[IPA_RULE_NON_HASHABLE]) == 0) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530335 WARN_ON_RATELIMIT_IPA(1);
336 IPAERR_RL("rt tbl %s is with zero total size\n", tbl->name);
Amir Levy9659e592016-10-27 18:08:27 +0300337 }
338
339 hdr_width = ipahal_get_hw_tbl_hdr_width();
340
341 if (tbl->sz[IPA_RULE_HASHABLE])
342 tbl->sz[IPA_RULE_HASHABLE] += hdr_width;
343 if (tbl->sz[IPA_RULE_NON_HASHABLE])
344 tbl->sz[IPA_RULE_NON_HASHABLE] += hdr_width;
345
346 IPADBG("RT tbl index %u hash_sz %u non-hash sz %u\n", tbl->idx,
347 tbl->sz[IPA_RULE_HASHABLE], tbl->sz[IPA_RULE_NON_HASHABLE]);
348
349 return 0;
350}
351
352/**
353 * ipa_generate_rt_hw_tbl_img() - generates the rt hw tbls.
354 * headers and bodies (sys bodies) are being created into buffers that will
355 * be filled into the local memory (sram)
356 * @ip: the ip address family type
357 * @alloc_params: IN/OUT parameters to hold info regard the tables headers
358 * and bodies on DDR (DMA buffers), and needed info for the allocation
359 * that the HAL needs
360 *
361 * Return: 0 on success, negative on failure
362 */
363static int ipa_generate_rt_hw_tbl_img(enum ipa_ip_type ip,
364 struct ipahal_fltrt_alloc_imgs_params *alloc_params)
365{
366 u32 hash_bdy_start_ofst, nhash_bdy_start_ofst;
367 u32 apps_start_idx;
368 int rc = 0;
369
370 if (ip == IPA_IP_v4) {
371 nhash_bdy_start_ofst = IPA_MEM_PART(apps_v4_rt_nhash_ofst) -
372 IPA_MEM_PART(v4_rt_nhash_ofst);
373 hash_bdy_start_ofst = IPA_MEM_PART(apps_v4_rt_hash_ofst) -
374 IPA_MEM_PART(v4_rt_hash_ofst);
375 apps_start_idx = IPA_MEM_PART(v4_apps_rt_index_lo);
376 } else {
377 nhash_bdy_start_ofst = IPA_MEM_PART(apps_v6_rt_nhash_ofst) -
378 IPA_MEM_PART(v6_rt_nhash_ofst);
379 hash_bdy_start_ofst = IPA_MEM_PART(apps_v6_rt_hash_ofst) -
380 IPA_MEM_PART(v6_rt_hash_ofst);
381 apps_start_idx = IPA_MEM_PART(v6_apps_rt_index_lo);
382 }
383
384 if (ipahal_fltrt_allocate_hw_tbl_imgs(alloc_params)) {
385 IPAERR("fail to allocate RT HW TBL images. IP %d\n", ip);
386 rc = -ENOMEM;
387 goto allocate_fail;
388 }
389
390 if (ipa_translate_rt_tbl_to_hw_fmt(ip, IPA_RULE_HASHABLE,
391 alloc_params->hash_bdy.base, alloc_params->hash_hdr.base,
392 hash_bdy_start_ofst, apps_start_idx)) {
393 IPAERR("fail to translate hashable rt tbls to hw format\n");
394 rc = -EPERM;
395 goto translate_fail;
396 }
397 if (ipa_translate_rt_tbl_to_hw_fmt(ip, IPA_RULE_NON_HASHABLE,
398 alloc_params->nhash_bdy.base, alloc_params->nhash_hdr.base,
399 nhash_bdy_start_ofst, apps_start_idx)) {
400 IPAERR("fail to translate non-hashable rt tbls to hw format\n");
401 rc = -EPERM;
402 goto translate_fail;
403 }
404
405 return rc;
406
407translate_fail:
408 if (alloc_params->hash_hdr.size)
409 ipahal_free_dma_mem(&alloc_params->hash_hdr);
410 ipahal_free_dma_mem(&alloc_params->nhash_hdr);
411 if (alloc_params->hash_bdy.size)
412 ipahal_free_dma_mem(&alloc_params->hash_bdy);
413 if (alloc_params->nhash_bdy.size)
414 ipahal_free_dma_mem(&alloc_params->nhash_bdy);
415allocate_fail:
416 return rc;
417}
418
419/**
420 * ipa_rt_valid_lcl_tbl_size() - validate if the space allocated for rt tbl
421 * bodies at the sram is enough for the commit
422 * @ipt: the ip address family type
423 * @rlt: the rule type (hashable or non-hashable)
424 *
425 * Return: true if enough space available or false in other cases
426 */
427static bool ipa_rt_valid_lcl_tbl_size(enum ipa_ip_type ipt,
428 enum ipa_rule_type rlt, struct ipa_mem_buffer *bdy)
429{
430 u16 avail;
431
432 if (ipt == IPA_IP_v4)
433 avail = (rlt == IPA_RULE_HASHABLE) ?
434 IPA_MEM_PART(apps_v4_rt_hash_size) :
435 IPA_MEM_PART(apps_v4_rt_nhash_size);
436 else
437 avail = (rlt == IPA_RULE_HASHABLE) ?
438 IPA_MEM_PART(apps_v6_rt_hash_size) :
439 IPA_MEM_PART(apps_v6_rt_nhash_size);
440
441 if (bdy->size <= avail)
442 return true;
443
444 IPAERR("tbl too big, needed %d avail %d ipt %d rlt %d\n",
445 bdy->size, avail, ipt, rlt);
446 return false;
447}
448
449/**
450 * __ipa_commit_rt_v3() - commit rt tables to the hw
451 * commit the headers and the bodies if are local with internal cache flushing
452 * @ipt: the ip address family type
453 *
454 * Return: 0 on success, negative on failure
455 */
456int __ipa_commit_rt_v3(enum ipa_ip_type ip)
457{
Amir Levy479cfdd2017-10-26 12:23:14 +0300458 struct ipa3_desc desc[IPA_RT_MAX_NUM_OF_COMMIT_TABLES_CMD_DESC];
Amir Levy9659e592016-10-27 18:08:27 +0300459 struct ipahal_imm_cmd_register_write reg_write_cmd = {0};
460 struct ipahal_imm_cmd_dma_shared_mem mem_cmd = {0};
Amir Levy479cfdd2017-10-26 12:23:14 +0300461 struct ipahal_imm_cmd_pyld
462 *cmd_pyld[IPA_RT_MAX_NUM_OF_COMMIT_TABLES_CMD_DESC];
Amir Levy9659e592016-10-27 18:08:27 +0300463 int num_cmd = 0;
464 struct ipahal_fltrt_alloc_imgs_params alloc_params;
465 u32 num_modem_rt_index;
466 int rc = 0;
467 u32 lcl_hash_hdr, lcl_nhash_hdr;
468 u32 lcl_hash_bdy, lcl_nhash_bdy;
469 bool lcl_hash, lcl_nhash;
470 struct ipahal_reg_fltrt_hash_flush flush;
471 struct ipahal_reg_valmask valmask;
472 int i;
473 struct ipa3_rt_tbl_set *set;
474 struct ipa3_rt_tbl *tbl;
475 u32 tbl_hdr_width;
476
477 tbl_hdr_width = ipahal_get_hw_tbl_hdr_width();
478 memset(desc, 0, sizeof(desc));
479 memset(cmd_pyld, 0, sizeof(cmd_pyld));
480 memset(&alloc_params, 0, sizeof(alloc_params));
481 alloc_params.ipt = ip;
482
483 if (ip == IPA_IP_v4) {
484 num_modem_rt_index =
485 IPA_MEM_PART(v4_modem_rt_index_hi) -
486 IPA_MEM_PART(v4_modem_rt_index_lo) + 1;
487 lcl_hash_hdr = ipa3_ctx->smem_restricted_bytes +
488 IPA_MEM_PART(v4_rt_hash_ofst) +
489 num_modem_rt_index * tbl_hdr_width;
490 lcl_nhash_hdr = ipa3_ctx->smem_restricted_bytes +
491 IPA_MEM_PART(v4_rt_nhash_ofst) +
492 num_modem_rt_index * tbl_hdr_width;
493 lcl_hash_bdy = ipa3_ctx->smem_restricted_bytes +
494 IPA_MEM_PART(apps_v4_rt_hash_ofst);
495 lcl_nhash_bdy = ipa3_ctx->smem_restricted_bytes +
496 IPA_MEM_PART(apps_v4_rt_nhash_ofst);
497 lcl_hash = ipa3_ctx->ip4_rt_tbl_hash_lcl;
498 lcl_nhash = ipa3_ctx->ip4_rt_tbl_nhash_lcl;
499 alloc_params.tbls_num = IPA_MEM_PART(v4_apps_rt_index_hi) -
500 IPA_MEM_PART(v4_apps_rt_index_lo) + 1;
501 } else {
502 num_modem_rt_index =
503 IPA_MEM_PART(v6_modem_rt_index_hi) -
504 IPA_MEM_PART(v6_modem_rt_index_lo) + 1;
505 lcl_hash_hdr = ipa3_ctx->smem_restricted_bytes +
506 IPA_MEM_PART(v6_rt_hash_ofst) +
507 num_modem_rt_index * tbl_hdr_width;
508 lcl_nhash_hdr = ipa3_ctx->smem_restricted_bytes +
509 IPA_MEM_PART(v6_rt_nhash_ofst) +
510 num_modem_rt_index * tbl_hdr_width;
511 lcl_hash_bdy = ipa3_ctx->smem_restricted_bytes +
512 IPA_MEM_PART(apps_v6_rt_hash_ofst);
513 lcl_nhash_bdy = ipa3_ctx->smem_restricted_bytes +
514 IPA_MEM_PART(apps_v6_rt_nhash_ofst);
515 lcl_hash = ipa3_ctx->ip6_rt_tbl_hash_lcl;
516 lcl_nhash = ipa3_ctx->ip6_rt_tbl_nhash_lcl;
517 alloc_params.tbls_num = IPA_MEM_PART(v6_apps_rt_index_hi) -
518 IPA_MEM_PART(v6_apps_rt_index_lo) + 1;
519 }
520
521 if (!ipa3_ctx->rt_idx_bitmap[ip]) {
522 IPAERR("no rt tbls present\n");
523 rc = -EPERM;
524 goto no_rt_tbls;
525 }
526
527 set = &ipa3_ctx->rt_tbl_set[ip];
528 list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
529 if (ipa_prep_rt_tbl_for_cmt(ip, tbl)) {
530 rc = -EPERM;
531 goto no_rt_tbls;
532 }
533 if (!tbl->in_sys[IPA_RULE_HASHABLE] &&
534 tbl->sz[IPA_RULE_HASHABLE]) {
535 alloc_params.num_lcl_hash_tbls++;
536 alloc_params.total_sz_lcl_hash_tbls +=
537 tbl->sz[IPA_RULE_HASHABLE];
538 alloc_params.total_sz_lcl_hash_tbls -= tbl_hdr_width;
539 }
540 if (!tbl->in_sys[IPA_RULE_NON_HASHABLE] &&
541 tbl->sz[IPA_RULE_NON_HASHABLE]) {
542 alloc_params.num_lcl_nhash_tbls++;
543 alloc_params.total_sz_lcl_nhash_tbls +=
544 tbl->sz[IPA_RULE_NON_HASHABLE];
545 alloc_params.total_sz_lcl_nhash_tbls -= tbl_hdr_width;
546 }
547 }
548
549 if (ipa_generate_rt_hw_tbl_img(ip, &alloc_params)) {
550 IPAERR("fail to generate RT HW TBL images. IP %d\n", ip);
551 rc = -EFAULT;
552 goto no_rt_tbls;
553 }
554
555 if (!ipa_rt_valid_lcl_tbl_size(ip, IPA_RULE_HASHABLE,
556 &alloc_params.hash_bdy)) {
557 rc = -EFAULT;
558 goto fail_size_valid;
559 }
560 if (!ipa_rt_valid_lcl_tbl_size(ip, IPA_RULE_NON_HASHABLE,
561 &alloc_params.nhash_bdy)) {
562 rc = -EFAULT;
563 goto fail_size_valid;
564 }
565
566 /* flushing ipa internal hashable rt rules cache */
567 memset(&flush, 0, sizeof(flush));
568 if (ip == IPA_IP_v4)
569 flush.v4_rt = true;
570 else
571 flush.v6_rt = true;
572 ipahal_get_fltrt_hash_flush_valmask(&flush, &valmask);
573 reg_write_cmd.skip_pipeline_clear = false;
574 reg_write_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
575 reg_write_cmd.offset = ipahal_get_reg_ofst(IPA_FILT_ROUT_HASH_FLUSH);
576 reg_write_cmd.value = valmask.val;
577 reg_write_cmd.value_mask = valmask.mask;
578 cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
579 IPA_IMM_CMD_REGISTER_WRITE, &reg_write_cmd, false);
580 if (!cmd_pyld[num_cmd]) {
581 IPAERR("fail construct register_write imm cmd. IP %d\n", ip);
582 goto fail_size_valid;
583 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300584 ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
Amir Levy9659e592016-10-27 18:08:27 +0300585 num_cmd++;
586
587 mem_cmd.is_read = false;
588 mem_cmd.skip_pipeline_clear = false;
589 mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
590 mem_cmd.size = alloc_params.nhash_hdr.size;
591 mem_cmd.system_addr = alloc_params.nhash_hdr.phys_base;
592 mem_cmd.local_addr = lcl_nhash_hdr;
593 cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
594 IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
595 if (!cmd_pyld[num_cmd]) {
596 IPAERR("fail construct dma_shared_mem imm cmd. IP %d\n", ip);
597 goto fail_imm_cmd_construct;
598 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300599 ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
Amir Levy9659e592016-10-27 18:08:27 +0300600 num_cmd++;
601
602 mem_cmd.is_read = false;
603 mem_cmd.skip_pipeline_clear = false;
604 mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
605 mem_cmd.size = alloc_params.hash_hdr.size;
606 mem_cmd.system_addr = alloc_params.hash_hdr.phys_base;
607 mem_cmd.local_addr = lcl_hash_hdr;
608 cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
609 IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
610 if (!cmd_pyld[num_cmd]) {
611 IPAERR("fail construct dma_shared_mem imm cmd. IP %d\n", ip);
612 goto fail_imm_cmd_construct;
613 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300614 ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
Amir Levy9659e592016-10-27 18:08:27 +0300615 num_cmd++;
616
617 if (lcl_nhash) {
Amir Levy479cfdd2017-10-26 12:23:14 +0300618 if (num_cmd >= IPA_RT_MAX_NUM_OF_COMMIT_TABLES_CMD_DESC) {
619 IPAERR("number of commands is out of range: IP = %d\n",
620 ip);
621 rc = -ENOBUFS;
622 goto fail_imm_cmd_construct;
623 }
624
Amir Levy9659e592016-10-27 18:08:27 +0300625 mem_cmd.is_read = false;
626 mem_cmd.skip_pipeline_clear = false;
627 mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
628 mem_cmd.size = alloc_params.nhash_bdy.size;
629 mem_cmd.system_addr = alloc_params.nhash_bdy.phys_base;
630 mem_cmd.local_addr = lcl_nhash_bdy;
631 cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
632 IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
633 if (!cmd_pyld[num_cmd]) {
634 IPAERR("fail construct dma_shared_mem cmd. IP %d\n",
635 ip);
636 goto fail_imm_cmd_construct;
637 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300638 ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
Amir Levy9659e592016-10-27 18:08:27 +0300639 num_cmd++;
640 }
641 if (lcl_hash) {
Amir Levy479cfdd2017-10-26 12:23:14 +0300642 if (num_cmd >= IPA_RT_MAX_NUM_OF_COMMIT_TABLES_CMD_DESC) {
643 IPAERR("number of commands is out of range: IP = %d\n",
644 ip);
645 rc = -ENOBUFS;
646 goto fail_imm_cmd_construct;
647 }
648
Amir Levy9659e592016-10-27 18:08:27 +0300649 mem_cmd.is_read = false;
650 mem_cmd.skip_pipeline_clear = false;
651 mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
652 mem_cmd.size = alloc_params.hash_bdy.size;
653 mem_cmd.system_addr = alloc_params.hash_bdy.phys_base;
654 mem_cmd.local_addr = lcl_hash_bdy;
655 cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
656 IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
657 if (!cmd_pyld[num_cmd]) {
658 IPAERR("fail construct dma_shared_mem cmd. IP %d\n",
659 ip);
660 goto fail_imm_cmd_construct;
661 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300662 ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
Amir Levy9659e592016-10-27 18:08:27 +0300663 num_cmd++;
664 }
665
666 if (ipa3_send_cmd(num_cmd, desc)) {
667 IPAERR("fail to send immediate command\n");
668 rc = -EFAULT;
669 goto fail_imm_cmd_construct;
670 }
671
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200672 IPADBG_LOW("Hashable HEAD\n");
Amir Levy9659e592016-10-27 18:08:27 +0300673 IPA_DUMP_BUFF(alloc_params.hash_hdr.base,
674 alloc_params.hash_hdr.phys_base, alloc_params.hash_hdr.size);
675
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200676 IPADBG_LOW("Non-Hashable HEAD\n");
Amir Levy9659e592016-10-27 18:08:27 +0300677 IPA_DUMP_BUFF(alloc_params.nhash_hdr.base,
678 alloc_params.nhash_hdr.phys_base, alloc_params.nhash_hdr.size);
679
680 if (alloc_params.hash_bdy.size) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200681 IPADBG_LOW("Hashable BODY\n");
Amir Levy9659e592016-10-27 18:08:27 +0300682 IPA_DUMP_BUFF(alloc_params.hash_bdy.base,
683 alloc_params.hash_bdy.phys_base,
684 alloc_params.hash_bdy.size);
685 }
686
687 if (alloc_params.nhash_bdy.size) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200688 IPADBG_LOW("Non-Hashable BODY\n");
Amir Levy9659e592016-10-27 18:08:27 +0300689 IPA_DUMP_BUFF(alloc_params.nhash_bdy.base,
690 alloc_params.nhash_bdy.phys_base,
691 alloc_params.nhash_bdy.size);
692 }
693
694 __ipa_reap_sys_rt_tbls(ip);
695
696fail_imm_cmd_construct:
697 for (i = 0 ; i < num_cmd ; i++)
698 ipahal_destroy_imm_cmd(cmd_pyld[i]);
699fail_size_valid:
700 if (alloc_params.hash_hdr.size)
701 ipahal_free_dma_mem(&alloc_params.hash_hdr);
702 ipahal_free_dma_mem(&alloc_params.nhash_hdr);
703 if (alloc_params.hash_bdy.size)
704 ipahal_free_dma_mem(&alloc_params.hash_bdy);
705 if (alloc_params.nhash_bdy.size)
706 ipahal_free_dma_mem(&alloc_params.nhash_bdy);
707
708no_rt_tbls:
709 return rc;
710}
711
712/**
713 * __ipa3_find_rt_tbl() - find the routing table
714 * which name is given as parameter
715 * @ip: [in] the ip address family type of the wanted routing table
716 * @name: [in] the name of the wanted routing table
717 *
718 * Returns: the routing table which name is given as parameter, or NULL if it
719 * doesn't exist
720 */
721struct ipa3_rt_tbl *__ipa3_find_rt_tbl(enum ipa_ip_type ip, const char *name)
722{
723 struct ipa3_rt_tbl *entry;
724 struct ipa3_rt_tbl_set *set;
725
726 if (strnlen(name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530727 IPAERR_RL("Name too long: %s\n", name);
Amir Levy9659e592016-10-27 18:08:27 +0300728 return NULL;
729 }
730
731 set = &ipa3_ctx->rt_tbl_set[ip];
732 list_for_each_entry(entry, &set->head_rt_tbl_list, link) {
733 if (!strcmp(name, entry->name))
734 return entry;
735 }
736
737 return NULL;
738}
739
740/**
741 * ipa3_query_rt_index() - find the routing table index
742 * which name and ip type are given as parameters
743 * @in: [out] the index of the wanted routing table
744 *
745 * Returns: the routing table which name is given as parameter, or NULL if it
746 * doesn't exist
747 */
748int ipa3_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in)
749{
750 struct ipa3_rt_tbl *entry;
751
752 if (in->ip >= IPA_IP_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530753 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +0300754 return -EINVAL;
755 }
756
Mohammed Javid47193a12017-06-15 18:39:07 +0530757 mutex_lock(&ipa3_ctx->lock);
Mohammed Javidcd665892017-10-11 17:05:57 +0530758 in->name[IPA_RESOURCE_NAME_MAX-1] = '\0';
Amir Levy9659e592016-10-27 18:08:27 +0300759 /* check if this table exists */
760 entry = __ipa3_find_rt_tbl(in->ip, in->name);
Mohammed Javid47193a12017-06-15 18:39:07 +0530761 if (!entry) {
762 mutex_unlock(&ipa3_ctx->lock);
Amir Levy9659e592016-10-27 18:08:27 +0300763 return -EFAULT;
Mohammed Javid47193a12017-06-15 18:39:07 +0530764 }
Amir Levy9659e592016-10-27 18:08:27 +0300765 in->idx = entry->idx;
Mohammed Javid47193a12017-06-15 18:39:07 +0530766 mutex_unlock(&ipa3_ctx->lock);
Amir Levy9659e592016-10-27 18:08:27 +0300767 return 0;
768}
769
770static struct ipa3_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip,
771 const char *name)
772{
773 struct ipa3_rt_tbl *entry;
774 struct ipa3_rt_tbl_set *set;
775 int i;
776 int id;
777 int max_tbl_indx;
778
779 if (name == NULL) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530780 IPAERR_RL("no tbl name\n");
Amir Levy9659e592016-10-27 18:08:27 +0300781 goto error;
782 }
783
784 if (ip == IPA_IP_v4) {
785 max_tbl_indx =
786 max(IPA_MEM_PART(v4_modem_rt_index_hi),
787 IPA_MEM_PART(v4_apps_rt_index_hi));
788 } else if (ip == IPA_IP_v6) {
789 max_tbl_indx =
790 max(IPA_MEM_PART(v6_modem_rt_index_hi),
791 IPA_MEM_PART(v6_apps_rt_index_hi));
792 } else {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530793 IPAERR_RL("bad ip family type\n");
Amir Levy9659e592016-10-27 18:08:27 +0300794 goto error;
795 }
796
797 set = &ipa3_ctx->rt_tbl_set[ip];
798 /* check if this table exists */
799 entry = __ipa3_find_rt_tbl(ip, name);
800 if (!entry) {
801 entry = kmem_cache_zalloc(ipa3_ctx->rt_tbl_cache, GFP_KERNEL);
802 if (!entry) {
803 IPAERR("failed to alloc RT tbl object\n");
804 goto error;
805 }
806 /* find a routing tbl index */
807 for (i = 0; i < IPA_RT_INDEX_BITMAP_SIZE; i++) {
808 if (!test_bit(i, &ipa3_ctx->rt_idx_bitmap[ip])) {
809 entry->idx = i;
810 set_bit(i, &ipa3_ctx->rt_idx_bitmap[ip]);
811 break;
812 }
813 }
814 if (i == IPA_RT_INDEX_BITMAP_SIZE) {
815 IPAERR("not free RT tbl indices left\n");
816 goto fail_rt_idx_alloc;
817 }
818 if (i > max_tbl_indx) {
819 IPAERR("rt tbl index is above max\n");
820 goto fail_rt_idx_alloc;
821 }
822
823 INIT_LIST_HEAD(&entry->head_rt_rule_list);
824 INIT_LIST_HEAD(&entry->link);
825 strlcpy(entry->name, name, IPA_RESOURCE_NAME_MAX);
826 entry->set = set;
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530827 entry->cookie = IPA_RT_TBL_COOKIE;
Amir Levy9659e592016-10-27 18:08:27 +0300828 entry->in_sys[IPA_RULE_HASHABLE] = (ip == IPA_IP_v4) ?
829 !ipa3_ctx->ip4_rt_tbl_hash_lcl :
830 !ipa3_ctx->ip6_rt_tbl_hash_lcl;
831 entry->in_sys[IPA_RULE_NON_HASHABLE] = (ip == IPA_IP_v4) ?
832 !ipa3_ctx->ip4_rt_tbl_nhash_lcl :
833 !ipa3_ctx->ip6_rt_tbl_nhash_lcl;
834 set->tbl_cnt++;
Skylar Chang0c37f5f2017-07-24 10:22:53 -0700835 entry->rule_ids = &set->rule_ids;
Amir Levy9659e592016-10-27 18:08:27 +0300836 list_add(&entry->link, &set->head_rt_tbl_list);
837
838 IPADBG("add rt tbl idx=%d tbl_cnt=%d ip=%d\n", entry->idx,
839 set->tbl_cnt, ip);
840
841 id = ipa3_id_alloc(entry);
842 if (id < 0) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530843 IPAERR_RL("failed to add to tree\n");
844 WARN_ON_RATELIMIT_IPA(1);
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530845 goto ipa_insert_failed;
Amir Levy9659e592016-10-27 18:08:27 +0300846 }
847 entry->id = id;
848 }
849
850 return entry;
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530851ipa_insert_failed:
852 set->tbl_cnt--;
853 list_del(&entry->link);
Skylar Chang0c37f5f2017-07-24 10:22:53 -0700854 idr_destroy(entry->rule_ids);
Amir Levy9659e592016-10-27 18:08:27 +0300855fail_rt_idx_alloc:
856 entry->cookie = 0;
857 kmem_cache_free(ipa3_ctx->rt_tbl_cache, entry);
858error:
859 return NULL;
860}
861
862static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry)
863{
864 enum ipa_ip_type ip = IPA_IP_MAX;
865 u32 id;
866 struct ipa3_rt_tbl_set *rset;
867
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530868 if (entry == NULL || (entry->cookie != IPA_RT_TBL_COOKIE)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530869 IPAERR_RL("bad parms\n");
Amir Levy9659e592016-10-27 18:08:27 +0300870 return -EINVAL;
871 }
872 id = entry->id;
873 if (ipa3_id_find(id) == NULL) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530874 IPAERR_RL("lookup failed\n");
Amir Levy9659e592016-10-27 18:08:27 +0300875 return -EPERM;
876 }
877
878 if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v4])
879 ip = IPA_IP_v4;
880 else if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v6])
881 ip = IPA_IP_v6;
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530882 else {
Mohammed Javida4252d82017-10-13 13:51:21 +0530883 WARN_ON_RATELIMIT_IPA(1);
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530884 return -EPERM;
885 }
Amir Levy9659e592016-10-27 18:08:27 +0300886
887 rset = &ipa3_ctx->reap_rt_tbl_set[ip];
888
Skylar Chang0c37f5f2017-07-24 10:22:53 -0700889 entry->rule_ids = NULL;
Amir Levy9659e592016-10-27 18:08:27 +0300890 if (entry->in_sys[IPA_RULE_HASHABLE] ||
891 entry->in_sys[IPA_RULE_NON_HASHABLE]) {
892 list_move(&entry->link, &rset->head_rt_tbl_list);
893 clear_bit(entry->idx, &ipa3_ctx->rt_idx_bitmap[ip]);
894 entry->set->tbl_cnt--;
895 IPADBG("del sys rt tbl_idx=%d tbl_cnt=%d ip=%d\n",
896 entry->idx, entry->set->tbl_cnt, ip);
897 } else {
898 list_del(&entry->link);
899 clear_bit(entry->idx, &ipa3_ctx->rt_idx_bitmap[ip]);
900 entry->set->tbl_cnt--;
901 IPADBG("del rt tbl_idx=%d tbl_cnt=%d ip=%d\n",
902 entry->idx, entry->set->tbl_cnt, ip);
903 kmem_cache_free(ipa3_ctx->rt_tbl_cache, entry);
904 }
905
906 /* remove the handle from the database */
907 ipa3_id_remove(id);
908 return 0;
909}
910
911static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule,
912 struct ipa3_hdr_entry **hdr,
913 struct ipa3_hdr_proc_ctx_entry **proc_ctx)
914{
915 if (rule->hdr_hdl && rule->hdr_proc_ctx_hdl) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530916 IPAERR_RL("rule contains both hdr_hdl and hdr_proc_ctx_hdl\n");
Amir Levy9659e592016-10-27 18:08:27 +0300917 return -EPERM;
918 }
919
920 if (rule->hdr_hdl) {
921 *hdr = ipa3_id_find(rule->hdr_hdl);
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530922 if ((*hdr == NULL) || ((*hdr)->cookie != IPA_HDR_COOKIE)) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530923 IPAERR_RL("rt rule does not point to valid hdr\n");
Amir Levy9659e592016-10-27 18:08:27 +0300924 return -EPERM;
925 }
926 } else if (rule->hdr_proc_ctx_hdl) {
927 *proc_ctx = ipa3_id_find(rule->hdr_proc_ctx_hdl);
928 if ((*proc_ctx == NULL) ||
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530929 ((*proc_ctx)->cookie != IPA_PROC_HDR_COOKIE)) {
Amir Levy9659e592016-10-27 18:08:27 +0300930
Mohammed Javida4252d82017-10-13 13:51:21 +0530931 IPAERR_RL("rt rule does not point to valid proc ctx\n");
Amir Levy9659e592016-10-27 18:08:27 +0300932 return -EPERM;
933 }
934 }
935
936 return 0;
937}
938
939static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry,
940 const struct ipa_rt_rule *rule,
941 struct ipa3_rt_tbl *tbl, struct ipa3_hdr_entry *hdr,
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +0530942 struct ipa3_hdr_proc_ctx_entry *proc_ctx,
Skylar Chang68c37d82018-04-07 16:42:36 -0700943 u16 rule_id, bool user)
Amir Levy9659e592016-10-27 18:08:27 +0300944{
945 int id;
946
947 *entry = kmem_cache_zalloc(ipa3_ctx->rt_rule_cache, GFP_KERNEL);
948 if (!*entry) {
949 IPAERR("failed to alloc RT rule object\n");
950 goto error;
951 }
952 INIT_LIST_HEAD(&(*entry)->link);
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530953 (*(entry))->cookie = IPA_RT_RULE_COOKIE;
Amir Levy9659e592016-10-27 18:08:27 +0300954 (*(entry))->rule = *rule;
955 (*(entry))->tbl = tbl;
956 (*(entry))->hdr = hdr;
957 (*(entry))->proc_ctx = proc_ctx;
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +0530958 if (rule_id) {
959 id = rule_id;
960 (*(entry))->rule_id_valid = 1;
961 } else {
962 id = ipa3_alloc_rule_id(tbl->rule_ids);
963 if (id < 0) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530964 IPAERR_RL("failed to allocate rule id\n");
965 WARN_ON_RATELIMIT_IPA(1);
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +0530966 goto alloc_rule_id_fail;
967 }
Amir Levy9659e592016-10-27 18:08:27 +0300968 }
969 (*(entry))->rule_id = id;
Skylar Chang68c37d82018-04-07 16:42:36 -0700970 (*(entry))->ipacm_installed = user;
Amir Levy9659e592016-10-27 18:08:27 +0300971
972 return 0;
973
974alloc_rule_id_fail:
975 kmem_cache_free(ipa3_ctx->rt_rule_cache, *entry);
976error:
977 return -EPERM;
978}
979
980static int __ipa_finish_rt_rule_add(struct ipa3_rt_entry *entry, u32 *rule_hdl,
981 struct ipa3_rt_tbl *tbl)
982{
983 int id;
984
985 tbl->rule_cnt++;
986 if (entry->hdr)
987 entry->hdr->ref_cnt++;
988 else if (entry->proc_ctx)
989 entry->proc_ctx->ref_cnt++;
990 id = ipa3_id_alloc(entry);
991 if (id < 0) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530992 IPAERR_RL("failed to add to tree\n");
993 WARN_ON_RATELIMIT_IPA(1);
Amir Levy9659e592016-10-27 18:08:27 +0300994 goto ipa_insert_failed;
995 }
996 IPADBG("add rt rule tbl_idx=%d rule_cnt=%d rule_id=%d\n",
997 tbl->idx, tbl->rule_cnt, entry->rule_id);
998 *rule_hdl = id;
999 entry->id = id;
1000
1001 return 0;
1002
1003ipa_insert_failed:
1004 if (entry->hdr)
1005 entry->hdr->ref_cnt--;
1006 else if (entry->proc_ctx)
1007 entry->proc_ctx->ref_cnt--;
Skylar Chang0c37f5f2017-07-24 10:22:53 -07001008 idr_remove(tbl->rule_ids, entry->rule_id);
Amir Levy9659e592016-10-27 18:08:27 +03001009 list_del(&entry->link);
1010 kmem_cache_free(ipa3_ctx->rt_rule_cache, entry);
1011 return -EPERM;
1012}
1013
1014static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05301015 const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl,
Skylar Chang68c37d82018-04-07 16:42:36 -07001016 u16 rule_id, bool user)
Amir Levy9659e592016-10-27 18:08:27 +03001017{
1018 struct ipa3_rt_tbl *tbl;
1019 struct ipa3_rt_entry *entry;
1020 struct ipa3_hdr_entry *hdr = NULL;
1021 struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;
1022
1023 if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx))
1024 goto error;
1025
1026
1027 tbl = __ipa_add_rt_tbl(ip, name);
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301028 if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301029 IPAERR_RL("failed adding rt tbl name = %s\n",
Amir Levy9659e592016-10-27 18:08:27 +03001030 name ? name : "");
1031 goto error;
1032 }
1033 /*
1034 * do not allow any rules to be added at end of the "default" routing
1035 * tables
1036 */
1037 if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) &&
1038 (tbl->rule_cnt > 0) && (at_rear != 0)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301039 IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d at_rear=%d"
1040 , tbl->rule_cnt, at_rear);
Amir Levy9659e592016-10-27 18:08:27 +03001041 goto error;
1042 }
1043
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05301044 if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx,
Skylar Chang68c37d82018-04-07 16:42:36 -07001045 rule_id, user))
Amir Levy9659e592016-10-27 18:08:27 +03001046 goto error;
1047
1048 if (at_rear)
1049 list_add_tail(&entry->link, &tbl->head_rt_rule_list);
1050 else
1051 list_add(&entry->link, &tbl->head_rt_rule_list);
1052
1053 if (__ipa_finish_rt_rule_add(entry, rule_hdl, tbl))
1054 goto error;
1055
1056 return 0;
1057
1058error:
1059 return -EPERM;
1060}
1061
1062static int __ipa_add_rt_rule_after(struct ipa3_rt_tbl *tbl,
1063 const struct ipa_rt_rule *rule, u32 *rule_hdl,
1064 struct ipa3_rt_entry **add_after_entry)
1065{
1066 struct ipa3_rt_entry *entry;
1067 struct ipa3_hdr_entry *hdr = NULL;
1068 struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;
1069
1070 if (!*add_after_entry)
1071 goto error;
1072
1073 if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx))
1074 goto error;
1075
Skylar Chang68c37d82018-04-07 16:42:36 -07001076 if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx, 0, true))
Amir Levy9659e592016-10-27 18:08:27 +03001077 goto error;
1078
1079 list_add(&entry->link, &((*add_after_entry)->link));
1080
1081 if (__ipa_finish_rt_rule_add(entry, rule_hdl, tbl))
1082 goto error;
1083
1084 /*
1085 * prepare for next insertion
1086 */
1087 *add_after_entry = entry;
1088
1089 return 0;
1090
1091error:
1092 *add_after_entry = NULL;
1093 return -EPERM;
1094}
1095
1096/**
1097 * ipa3_add_rt_rule() - Add the specified routing rules to SW and optionally
1098 * commit to IPA HW
1099 * @rules: [inout] set of routing rules to add
1100 *
1101 * Returns: 0 on success, negative on failure
1102 *
1103 * Note: Should not be called from atomic context
1104 */
Skylar Chang68c37d82018-04-07 16:42:36 -07001105
Amir Levy9659e592016-10-27 18:08:27 +03001106int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules)
1107{
Skylar Chang68c37d82018-04-07 16:42:36 -07001108 return ipa3_add_rt_rule_usr(rules, false);
1109}
1110/**
1111 * ipa3_add_rt_rule_usr() - Add the specified routing rules to SW and optionally
1112 * commit to IPA HW
1113 * @rules: [inout] set of routing rules to add
1114 * @user_only: [in] indicate installed by userspace module
1115 *
1116 * Returns: 0 on success, negative on failure
1117 *
1118 * Note: Should not be called from atomic context
1119 */
1120
1121int ipa3_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, bool user_only)
1122{
Amir Levy9659e592016-10-27 18:08:27 +03001123 int i;
1124 int ret;
1125
1126 if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301127 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +03001128 return -EINVAL;
1129 }
1130
1131 mutex_lock(&ipa3_ctx->lock);
1132 for (i = 0; i < rules->num_rules; i++) {
Mohammed Javidcd665892017-10-11 17:05:57 +05301133 rules->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
Amir Levy9659e592016-10-27 18:08:27 +03001134 if (__ipa_add_rt_rule(rules->ip, rules->rt_tbl_name,
1135 &rules->rules[i].rule,
1136 rules->rules[i].at_rear,
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05301137 &rules->rules[i].rt_rule_hdl,
Skylar Chang68c37d82018-04-07 16:42:36 -07001138 0,
1139 user_only)) {
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05301140 IPAERR("failed to add rt rule %d\n", i);
1141 rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
1142 } else {
1143 rules->rules[i].status = 0;
1144 }
1145 }
1146
1147 if (rules->commit)
1148 if (ipa3_ctx->ctrl->ipa3_commit_rt(rules->ip)) {
1149 ret = -EPERM;
1150 goto bail;
1151 }
1152
1153 ret = 0;
1154bail:
1155 mutex_unlock(&ipa3_ctx->lock);
1156 return ret;
1157}
1158
1159/**
1160 * ipa3_add_rt_rule_ext() - Add the specified routing rules to SW with rule id
1161 * and optionally commit to IPA HW
1162 * @rules: [inout] set of routing rules to add
1163 *
1164 * Returns: 0 on success, negative on failure
1165 *
1166 * Note: Should not be called from atomic context
1167 */
1168int ipa3_add_rt_rule_ext(struct ipa_ioc_add_rt_rule_ext *rules)
1169{
1170 int i;
1171 int ret;
1172
1173 if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) {
1174 IPAERR("bad parm\n");
1175 return -EINVAL;
1176 }
1177
1178 mutex_lock(&ipa3_ctx->lock);
1179 for (i = 0; i < rules->num_rules; i++) {
1180 if (__ipa_add_rt_rule(rules->ip, rules->rt_tbl_name,
1181 &rules->rules[i].rule,
1182 rules->rules[i].at_rear,
1183 &rules->rules[i].rt_rule_hdl,
Skylar Chang68c37d82018-04-07 16:42:36 -07001184 rules->rules[i].rule_id, true)) {
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05301185 IPAERR("failed to add rt rule %d\n", i);
Amir Levy9659e592016-10-27 18:08:27 +03001186 rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
1187 } else {
1188 rules->rules[i].status = 0;
1189 }
1190 }
1191
1192 if (rules->commit)
1193 if (ipa3_ctx->ctrl->ipa3_commit_rt(rules->ip)) {
1194 ret = -EPERM;
1195 goto bail;
1196 }
1197
1198 ret = 0;
1199bail:
1200 mutex_unlock(&ipa3_ctx->lock);
1201 return ret;
1202}
1203
1204/**
1205 * ipa3_add_rt_rule_after() - Add the given routing rules after the
1206 * specified rule to SW and optionally commit to IPA HW
1207 * @rules: [inout] set of routing rules to add + handle where to add
1208 *
1209 * Returns: 0 on success, negative on failure
1210 *
1211 * Note: Should not be called from atomic context
1212 */
1213int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules)
1214{
1215 int i;
1216 int ret = 0;
1217 struct ipa3_rt_tbl *tbl = NULL;
1218 struct ipa3_rt_entry *entry = NULL;
1219
1220 if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301221 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +03001222 return -EINVAL;
1223 }
1224
1225 mutex_lock(&ipa3_ctx->lock);
Mohammed Javidcd665892017-10-11 17:05:57 +05301226 rules->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
Amir Levy9659e592016-10-27 18:08:27 +03001227 tbl = __ipa3_find_rt_tbl(rules->ip, rules->rt_tbl_name);
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301228 if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301229 IPAERR_RL("failed finding rt tbl name = %s\n",
Amir Levy9659e592016-10-27 18:08:27 +03001230 rules->rt_tbl_name ? rules->rt_tbl_name : "");
1231 ret = -EINVAL;
1232 goto bail;
1233 }
1234
Amir Levy479cfdd2017-10-26 12:23:14 +03001235 if (!tbl->rule_cnt) {
1236 IPAERR_RL("tbl->rule_cnt == 0");
Amir Levy9659e592016-10-27 18:08:27 +03001237 ret = -EINVAL;
1238 goto bail;
1239 }
1240
1241 entry = ipa3_id_find(rules->add_after_hdl);
1242 if (!entry) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301243 IPAERR_RL("failed finding rule %d in rt tbls\n",
Amir Levy9659e592016-10-27 18:08:27 +03001244 rules->add_after_hdl);
1245 ret = -EINVAL;
1246 goto bail;
1247 }
1248
Mohammed Javidb7c859b2017-09-07 11:05:56 +05301249 if (entry->cookie != IPA_RT_RULE_COOKIE) {
1250 IPAERR_RL("Invalid cookie value = %u rule %d in rt tbls\n",
1251 entry->cookie, rules->add_after_hdl);
1252 ret = -EINVAL;
1253 goto bail;
1254 }
1255
Amir Levy9659e592016-10-27 18:08:27 +03001256 if (entry->tbl != tbl) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301257 IPAERR_RL("given rt rule does not match the table\n");
Amir Levy9659e592016-10-27 18:08:27 +03001258 ret = -EINVAL;
1259 goto bail;
1260 }
1261
1262 /*
1263 * do not allow any rules to be added at end of the "default" routing
1264 * tables
1265 */
1266 if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) &&
1267 (&entry->link == tbl->head_rt_rule_list.prev)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301268 IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d\n",
Amir Levy9659e592016-10-27 18:08:27 +03001269 tbl->rule_cnt);
1270 ret = -EINVAL;
1271 goto bail;
1272 }
1273
1274 /*
1275 * we add all rules one after the other, if one insertion fails, it cuts
1276 * the chain (all following will receive fail status) following calls to
1277 * __ipa_add_rt_rule_after will fail (entry == NULL)
1278 */
1279
1280 for (i = 0; i < rules->num_rules; i++) {
1281 if (__ipa_add_rt_rule_after(tbl,
1282 &rules->rules[i].rule,
1283 &rules->rules[i].rt_rule_hdl,
1284 &entry)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301285 IPAERR_RL("failed to add rt rule %d\n", i);
Amir Levy9659e592016-10-27 18:08:27 +03001286 rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
1287 } else {
1288 rules->rules[i].status = 0;
1289 }
1290 }
1291
1292 if (rules->commit)
1293 if (ipa3_ctx->ctrl->ipa3_commit_rt(rules->ip)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301294 IPAERR_RL("failed to commit\n");
Amir Levy9659e592016-10-27 18:08:27 +03001295 ret = -EPERM;
1296 goto bail;
1297 }
1298
1299 ret = 0;
1300 goto bail;
1301
1302bail:
1303 mutex_unlock(&ipa3_ctx->lock);
1304 return ret;
1305}
1306
1307int __ipa3_del_rt_rule(u32 rule_hdl)
1308{
1309 struct ipa3_rt_entry *entry;
1310 int id;
Mohammed Javid6f6eadb2018-02-20 16:01:26 +05301311 struct ipa3_hdr_entry *hdr_entry;
1312 struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
Amir Levy9659e592016-10-27 18:08:27 +03001313
1314 entry = ipa3_id_find(rule_hdl);
1315
1316 if (entry == NULL) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301317 IPAERR_RL("lookup failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03001318 return -EINVAL;
1319 }
1320
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301321 if (entry->cookie != IPA_RT_RULE_COOKIE) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301322 IPAERR_RL("bad params\n");
Amir Levy9659e592016-10-27 18:08:27 +03001323 return -EINVAL;
1324 }
1325
Ghanim Fodi5fd0c952018-01-31 14:49:37 +02001326 if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
1327 IPADBG("Deleting rule from default rt table idx=%u\n",
1328 entry->tbl->idx);
1329 if (entry->tbl->rule_cnt == 1) {
1330 IPAERR_RL("Default tbl last rule cannot be deleted\n");
1331 return -EINVAL;
1332 }
1333 }
1334
Mohammed Javid6f6eadb2018-02-20 16:01:26 +05301335 /* Adding check to confirm still
1336 * header entry present in header table or not
1337 */
1338
1339 if (entry->hdr) {
1340 hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
1341 if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
1342 IPAERR_RL("Header entry already deleted\n");
1343 return -EINVAL;
1344 }
1345 } else if (entry->proc_ctx) {
1346 hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
1347 if (!hdr_proc_entry ||
1348 hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
1349 IPAERR_RL("Proc header entry already deleted\n");
1350 return -EINVAL;
1351 }
1352 }
1353
Amir Levy9659e592016-10-27 18:08:27 +03001354 if (entry->hdr)
1355 __ipa3_release_hdr(entry->hdr->id);
1356 else if (entry->proc_ctx)
1357 __ipa3_release_hdr_proc_ctx(entry->proc_ctx->id);
1358 list_del(&entry->link);
1359 entry->tbl->rule_cnt--;
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001360 IPADBG("del rt rule tbl_idx=%d rule_cnt=%d rule_id=%d\n ref_cnt=%u",
1361 entry->tbl->idx, entry->tbl->rule_cnt,
1362 entry->rule_id, entry->tbl->ref_cnt);
Mohammed Javidd0c2a1e2017-10-30 15:34:22 +05301363 /* if rule id was allocated from idr, remove it */
1364 if (!entry->rule_id_valid)
1365 idr_remove(entry->tbl->rule_ids, entry->rule_id);
Amir Levy9659e592016-10-27 18:08:27 +03001366 if (entry->tbl->rule_cnt == 0 && entry->tbl->ref_cnt == 0) {
1367 if (__ipa_del_rt_tbl(entry->tbl))
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301368 IPAERR_RL("fail to del RT tbl\n");
Amir Levy9659e592016-10-27 18:08:27 +03001369 }
1370 entry->cookie = 0;
1371 id = entry->id;
1372 kmem_cache_free(ipa3_ctx->rt_rule_cache, entry);
1373
1374 /* remove the handle from the database */
1375 ipa3_id_remove(id);
1376
1377 return 0;
1378}
1379
1380/**
1381 * ipa3_del_rt_rule() - Remove the specified routing rules to SW and optionally
1382 * commit to IPA HW
1383 * @hdls: [inout] set of routing rules to delete
1384 *
1385 * Returns: 0 on success, negative on failure
1386 *
1387 * Note: Should not be called from atomic context
1388 */
1389int ipa3_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls)
1390{
1391 int i;
1392 int ret;
1393
1394 if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301395 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +03001396 return -EINVAL;
1397 }
1398
1399 mutex_lock(&ipa3_ctx->lock);
1400 for (i = 0; i < hdls->num_hdls; i++) {
1401 if (__ipa3_del_rt_rule(hdls->hdl[i].hdl)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301402 IPAERR_RL("failed to del rt rule %i\n", i);
Amir Levy9659e592016-10-27 18:08:27 +03001403 hdls->hdl[i].status = IPA_RT_STATUS_OF_DEL_FAILED;
1404 } else {
1405 hdls->hdl[i].status = 0;
1406 }
1407 }
1408
1409 if (hdls->commit)
1410 if (ipa3_ctx->ctrl->ipa3_commit_rt(hdls->ip)) {
1411 ret = -EPERM;
1412 goto bail;
1413 }
1414
1415 ret = 0;
1416bail:
1417 mutex_unlock(&ipa3_ctx->lock);
1418 return ret;
1419}
1420
1421/**
1422 * ipa_commit_rt_rule() - Commit the current SW routing table of specified type
1423 * to IPA HW
1424 * @ip: The family of routing tables
1425 *
1426 * Returns: 0 on success, negative on failure
1427 *
1428 * Note: Should not be called from atomic context
1429 */
1430int ipa3_commit_rt(enum ipa_ip_type ip)
1431{
1432 int ret;
1433
1434 if (ip >= IPA_IP_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301435 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +03001436 return -EINVAL;
1437 }
1438
1439 /*
1440 * issue a commit on the filtering module of same IP type since
1441 * filtering rules point to routing tables
1442 */
1443 if (ipa3_commit_flt(ip))
1444 return -EPERM;
1445
1446 mutex_lock(&ipa3_ctx->lock);
1447 if (ipa3_ctx->ctrl->ipa3_commit_rt(ip)) {
1448 ret = -EPERM;
1449 goto bail;
1450 }
1451
1452 ret = 0;
1453bail:
1454 mutex_unlock(&ipa3_ctx->lock);
1455 return ret;
1456}
1457
1458/**
1459 * ipa3_reset_rt() - reset the current SW routing table of specified type
1460 * (does not commit to HW)
Skylar Chang68c37d82018-04-07 16:42:36 -07001461 * @ip: [in] The family of routing tables
1462 * @user_only: [in] indicate delete rules installed by userspace
Amir Levy9659e592016-10-27 18:08:27 +03001463 *
1464 * Returns: 0 on success, negative on failure
1465 *
1466 * Note: Should not be called from atomic context
1467 */
Skylar Chang68c37d82018-04-07 16:42:36 -07001468int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only)
Amir Levy9659e592016-10-27 18:08:27 +03001469{
1470 struct ipa3_rt_tbl *tbl;
1471 struct ipa3_rt_tbl *tbl_next;
1472 struct ipa3_rt_tbl_set *set;
1473 struct ipa3_rt_entry *rule;
1474 struct ipa3_rt_entry *rule_next;
1475 struct ipa3_rt_tbl_set *rset;
1476 u32 apps_start_idx;
1477 int id;
Skylar Chang68c37d82018-04-07 16:42:36 -07001478 bool tbl_user = false;
Amir Levy9659e592016-10-27 18:08:27 +03001479
1480 if (ip >= IPA_IP_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301481 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +03001482 return -EINVAL;
1483 }
1484
1485 if (ip == IPA_IP_v4)
1486 apps_start_idx =
1487 IPA_MEM_PART(v4_apps_rt_index_lo);
1488 else
1489 apps_start_idx =
1490 IPA_MEM_PART(v6_apps_rt_index_lo);
1491
1492 /*
1493 * issue a reset on the filtering module of same IP type since
1494 * filtering rules point to routing tables
1495 */
Skylar Chang68c37d82018-04-07 16:42:36 -07001496 if (ipa3_reset_flt(ip, user_only))
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301497 IPAERR_RL("fail to reset flt ip=%d\n", ip);
Amir Levy9659e592016-10-27 18:08:27 +03001498
1499 set = &ipa3_ctx->rt_tbl_set[ip];
1500 rset = &ipa3_ctx->reap_rt_tbl_set[ip];
1501 mutex_lock(&ipa3_ctx->lock);
1502 IPADBG("reset rt ip=%d\n", ip);
1503 list_for_each_entry_safe(tbl, tbl_next, &set->head_rt_tbl_list, link) {
Skylar Chang68c37d82018-04-07 16:42:36 -07001504 tbl_user = false;
Amir Levy9659e592016-10-27 18:08:27 +03001505 list_for_each_entry_safe(rule, rule_next,
1506 &tbl->head_rt_rule_list, link) {
1507 if (ipa3_id_find(rule->id) == NULL) {
Mohammed Javida4252d82017-10-13 13:51:21 +05301508 WARN_ON_RATELIMIT_IPA(1);
Amir Levy9659e592016-10-27 18:08:27 +03001509 mutex_unlock(&ipa3_ctx->lock);
1510 return -EFAULT;
1511 }
1512
Skylar Chang68c37d82018-04-07 16:42:36 -07001513 /* indicate if tbl used for user-specified rules*/
1514 if (rule->ipacm_installed) {
1515 IPADBG("tbl_user %d, tbl-index %d\n",
1516 tbl_user, tbl->id);
1517 tbl_user = true;
1518 }
Amir Levy9659e592016-10-27 18:08:27 +03001519 /*
1520 * for the "default" routing tbl, remove all but the
1521 * last rule
1522 */
1523 if (tbl->idx == apps_start_idx && tbl->rule_cnt == 1)
1524 continue;
1525
Skylar Chang68c37d82018-04-07 16:42:36 -07001526 if (!user_only ||
1527 rule->ipacm_installed) {
1528 list_del(&rule->link);
1529 tbl->rule_cnt--;
1530 if (rule->hdr)
1531 __ipa3_release_hdr(rule->hdr->id);
1532 else if (rule->proc_ctx)
1533 __ipa3_release_hdr_proc_ctx(
1534 rule->proc_ctx->id);
1535 rule->cookie = 0;
1536 idr_remove(tbl->rule_ids, rule->rule_id);
1537 id = rule->id;
1538 kmem_cache_free(ipa3_ctx->rt_rule_cache, rule);
Amir Levy9659e592016-10-27 18:08:27 +03001539
Skylar Chang68c37d82018-04-07 16:42:36 -07001540 /* remove the handle from the database */
1541 ipa3_id_remove(id);
1542 }
Amir Levy9659e592016-10-27 18:08:27 +03001543 }
1544
1545 if (ipa3_id_find(tbl->id) == NULL) {
Mohammed Javida4252d82017-10-13 13:51:21 +05301546 WARN_ON_RATELIMIT_IPA(1);
Amir Levy9659e592016-10-27 18:08:27 +03001547 mutex_unlock(&ipa3_ctx->lock);
1548 return -EFAULT;
1549 }
1550 id = tbl->id;
1551
1552 /* do not remove the "default" routing tbl which has index 0 */
1553 if (tbl->idx != apps_start_idx) {
Skylar Chang68c37d82018-04-07 16:42:36 -07001554 if (!user_only || tbl_user) {
1555 tbl->rule_ids = NULL;
1556 if (tbl->in_sys[IPA_RULE_HASHABLE] ||
1557 tbl->in_sys[IPA_RULE_NON_HASHABLE]) {
1558 list_move(&tbl->link,
1559 &rset->head_rt_tbl_list);
1560 clear_bit(tbl->idx,
Amir Levy9659e592016-10-27 18:08:27 +03001561 &ipa3_ctx->rt_idx_bitmap[ip]);
Skylar Chang68c37d82018-04-07 16:42:36 -07001562 set->tbl_cnt--;
1563 IPADBG("rst tbl_idx=%d cnt=%d\n",
Amir Levy9659e592016-10-27 18:08:27 +03001564 tbl->idx, set->tbl_cnt);
Skylar Chang68c37d82018-04-07 16:42:36 -07001565 } else {
1566 list_del(&tbl->link);
1567 set->tbl_cnt--;
1568 clear_bit(tbl->idx,
Amir Levy9659e592016-10-27 18:08:27 +03001569 &ipa3_ctx->rt_idx_bitmap[ip]);
Skylar Chang68c37d82018-04-07 16:42:36 -07001570 IPADBG("rst rt tbl_idx=%d tbl_cnt=%d\n",
Amir Levy9659e592016-10-27 18:08:27 +03001571 tbl->idx, set->tbl_cnt);
Skylar Chang68c37d82018-04-07 16:42:36 -07001572 kmem_cache_free(ipa3_ctx->rt_tbl_cache,
1573 tbl);
1574 }
1575 /* remove the handle from the database */
1576 ipa3_id_remove(id);
Amir Levy9659e592016-10-27 18:08:27 +03001577 }
Amir Levy9659e592016-10-27 18:08:27 +03001578 }
1579 }
Skylar Chang5ec274f2018-05-03 02:18:34 -07001580
1581 /* commit the change to IPA-HW */
1582 if (ipa3_ctx->ctrl->ipa3_commit_rt(IPA_IP_v4) ||
1583 ipa3_ctx->ctrl->ipa3_commit_rt(IPA_IP_v6)) {
1584 IPAERR("fail to commit rt-rule\n");
1585 WARN_ON_RATELIMIT_IPA(1);
1586 mutex_unlock(&ipa3_ctx->lock);
1587 return -EPERM;
1588 }
Amir Levy9659e592016-10-27 18:08:27 +03001589 mutex_unlock(&ipa3_ctx->lock);
1590
1591 return 0;
1592}
1593
1594/**
1595 * ipa3_get_rt_tbl() - lookup the specified routing table and return handle if
1596 * it exists, if lookup succeeds the routing table ref cnt is increased
1597 * @lookup: [inout] routing table to lookup and its handle
1598 *
1599 * Returns: 0 on success, negative on failure
1600 *
1601 * Note: Should not be called from atomic context
1602 * Caller should call ipa3_put_rt_tbl later if this function succeeds
1603 */
1604int ipa3_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup)
1605{
1606 struct ipa3_rt_tbl *entry;
1607 int result = -EFAULT;
1608
1609 if (lookup == NULL || lookup->ip >= IPA_IP_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301610 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +03001611 return -EINVAL;
1612 }
1613 mutex_lock(&ipa3_ctx->lock);
Mohammed Javidcd665892017-10-11 17:05:57 +05301614 lookup->name[IPA_RESOURCE_NAME_MAX-1] = '\0';
Amir Levy9659e592016-10-27 18:08:27 +03001615 entry = __ipa3_find_rt_tbl(lookup->ip, lookup->name);
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301616 if (entry && entry->cookie == IPA_RT_TBL_COOKIE) {
Utkarsh Saxena69e4ab0b2017-04-25 17:39:41 +05301617 if (entry->ref_cnt == U32_MAX) {
Mohammed Javida4252d82017-10-13 13:51:21 +05301618 IPAERR_RL("fail: ref count crossed limit\n");
Utkarsh Saxena69e4ab0b2017-04-25 17:39:41 +05301619 goto ret;
1620 }
Amir Levy9659e592016-10-27 18:08:27 +03001621 entry->ref_cnt++;
1622 lookup->hdl = entry->id;
1623
1624 /* commit for get */
1625 if (ipa3_ctx->ctrl->ipa3_commit_rt(lookup->ip))
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301626 IPAERR_RL("fail to commit RT tbl\n");
Amir Levy9659e592016-10-27 18:08:27 +03001627
1628 result = 0;
1629 }
Utkarsh Saxena69e4ab0b2017-04-25 17:39:41 +05301630
1631ret:
Amir Levy9659e592016-10-27 18:08:27 +03001632 mutex_unlock(&ipa3_ctx->lock);
1633
1634 return result;
1635}
1636
1637/**
1638 * ipa3_put_rt_tbl() - Release the specified routing table handle
1639 * @rt_tbl_hdl: [in] the routing table handle to release
1640 *
1641 * Returns: 0 on success, negative on failure
1642 *
1643 * Note: Should not be called from atomic context
1644 */
1645int ipa3_put_rt_tbl(u32 rt_tbl_hdl)
1646{
1647 struct ipa3_rt_tbl *entry;
1648 enum ipa_ip_type ip = IPA_IP_MAX;
Mohammed Javid42ad67b2017-07-27 15:12:18 +05301649 int result = 0;
Amir Levy9659e592016-10-27 18:08:27 +03001650
1651 mutex_lock(&ipa3_ctx->lock);
1652 entry = ipa3_id_find(rt_tbl_hdl);
1653 if (entry == NULL) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301654 IPAERR_RL("lookup failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03001655 result = -EINVAL;
1656 goto ret;
1657 }
1658
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301659 if ((entry->cookie != IPA_RT_TBL_COOKIE) || entry->ref_cnt == 0) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301660 IPAERR_RL("bad parms\n");
Amir Levy9659e592016-10-27 18:08:27 +03001661 result = -EINVAL;
1662 goto ret;
1663 }
1664
1665 if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v4])
1666 ip = IPA_IP_v4;
1667 else if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v6])
1668 ip = IPA_IP_v6;
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301669 else {
Mohammed Javida4252d82017-10-13 13:51:21 +05301670 WARN_ON_RATELIMIT_IPA(1);
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301671 result = -EINVAL;
1672 goto ret;
1673 }
Amir Levy9659e592016-10-27 18:08:27 +03001674
1675 entry->ref_cnt--;
1676 if (entry->ref_cnt == 0 && entry->rule_cnt == 0) {
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001677 IPADBG("zero ref_cnt, delete rt tbl (idx=%u)\n",
1678 entry->idx);
Amir Levy9659e592016-10-27 18:08:27 +03001679 if (__ipa_del_rt_tbl(entry))
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301680 IPAERR_RL("fail to del RT tbl\n");
Amir Levy9659e592016-10-27 18:08:27 +03001681 /* commit for put */
1682 if (ipa3_ctx->ctrl->ipa3_commit_rt(ip))
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301683 IPAERR_RL("fail to commit RT tbl\n");
Amir Levy9659e592016-10-27 18:08:27 +03001684 }
1685
1686 result = 0;
1687
1688ret:
1689 mutex_unlock(&ipa3_ctx->lock);
1690
1691 return result;
1692}
1693
1694
1695static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
1696{
1697 struct ipa3_rt_entry *entry;
1698 struct ipa3_hdr_entry *hdr = NULL;
1699 struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;
Mohammed Javid6f6eadb2018-02-20 16:01:26 +05301700 struct ipa3_hdr_entry *hdr_entry;
1701 struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
Skylar Chang68c37d82018-04-07 16:42:36 -07001702
Amir Levy9659e592016-10-27 18:08:27 +03001703 if (rtrule->rule.hdr_hdl) {
1704 hdr = ipa3_id_find(rtrule->rule.hdr_hdl);
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301705 if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301706 IPAERR_RL("rt rule does not point to valid hdr\n");
Amir Levy9659e592016-10-27 18:08:27 +03001707 goto error;
1708 }
1709 } else if (rtrule->rule.hdr_proc_ctx_hdl) {
1710 proc_ctx = ipa3_id_find(rtrule->rule.hdr_proc_ctx_hdl);
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301711 if ((proc_ctx == NULL) ||
1712 (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301713 IPAERR_RL("rt rule does not point to valid proc ctx\n");
Amir Levy9659e592016-10-27 18:08:27 +03001714 goto error;
1715 }
1716 }
1717
1718 entry = ipa3_id_find(rtrule->rt_rule_hdl);
1719 if (entry == NULL) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301720 IPAERR_RL("lookup failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03001721 goto error;
1722 }
1723
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301724 if (entry->cookie != IPA_RT_RULE_COOKIE) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301725 IPAERR_RL("bad params\n");
Amir Levy9659e592016-10-27 18:08:27 +03001726 goto error;
1727 }
1728
Mohammed Javid6f6eadb2018-02-20 16:01:26 +05301729 /* Adding check to confirm still
1730 * header entry present in header table or not
1731 */
1732
1733 if (entry->hdr) {
1734 hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
1735 if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
1736 IPAERR_RL("Header entry already deleted\n");
1737 return -EPERM;
1738 }
1739 } else if (entry->proc_ctx) {
1740 hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
1741 if (!hdr_proc_entry ||
1742 hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
1743 IPAERR_RL("Proc header entry already deleted\n");
1744 return -EPERM;
1745 }
1746 }
1747
Amir Levy9659e592016-10-27 18:08:27 +03001748 if (entry->hdr)
1749 entry->hdr->ref_cnt--;
1750 if (entry->proc_ctx)
1751 entry->proc_ctx->ref_cnt--;
1752
1753 entry->rule = rtrule->rule;
1754 entry->hdr = hdr;
1755 entry->proc_ctx = proc_ctx;
1756
1757 if (entry->hdr)
1758 entry->hdr->ref_cnt++;
1759 if (entry->proc_ctx)
1760 entry->proc_ctx->ref_cnt++;
1761
1762 entry->hw_len = 0;
1763 entry->prio = 0;
1764
1765 return 0;
1766
1767error:
1768 return -EPERM;
1769}
1770
1771/**
1772 * ipa3_mdfy_rt_rule() - Modify the specified routing rules in SW and optionally
1773 * commit to IPA HW
1774 *
1775 * Returns: 0 on success, negative on failure
1776 *
1777 * Note: Should not be called from atomic context
1778 */
1779int ipa3_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *hdls)
1780{
1781 int i;
1782 int result;
1783
1784 if (hdls == NULL || hdls->num_rules == 0 || hdls->ip >= IPA_IP_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301785 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +03001786 return -EINVAL;
1787 }
1788
1789 mutex_lock(&ipa3_ctx->lock);
1790 for (i = 0; i < hdls->num_rules; i++) {
1791 if (__ipa_mdfy_rt_rule(&hdls->rules[i])) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301792 IPAERR_RL("failed to mdfy rt rule %i\n", i);
Amir Levy9659e592016-10-27 18:08:27 +03001793 hdls->rules[i].status = IPA_RT_STATUS_OF_MDFY_FAILED;
1794 } else {
1795 hdls->rules[i].status = 0;
1796 }
1797 }
1798
1799 if (hdls->commit)
1800 if (ipa3_ctx->ctrl->ipa3_commit_rt(hdls->ip)) {
1801 result = -EPERM;
1802 goto bail;
1803 }
1804 result = 0;
1805bail:
1806 mutex_unlock(&ipa3_ctx->lock);
1807
1808 return result;
1809}
1810
1811/**
1812 * ipa3_set_rt_tuple_mask() - Sets the rt tuple masking for the given tbl
1813 * table index must be for AP EP (not modem)
1814 * updates the the routing masking values without changing the flt ones.
1815 *
1816 * @tbl_idx: routing table index to configure the tuple masking
1817 * @tuple: the tuple members masking
1818 * Returns: 0 on success, negative on failure
1819 *
1820 */
1821int ipa3_set_rt_tuple_mask(int tbl_idx, struct ipahal_reg_hash_tuple *tuple)
1822{
1823 struct ipahal_reg_fltrt_hash_tuple fltrt_tuple;
1824
1825 if (!tuple) {
1826 IPAERR("bad tuple\n");
1827 return -EINVAL;
1828 }
1829
1830 if (tbl_idx >=
1831 max(IPA_MEM_PART(v6_rt_num_index),
1832 IPA_MEM_PART(v4_rt_num_index)) ||
1833 tbl_idx < 0) {
1834 IPAERR("bad table index\n");
1835 return -EINVAL;
1836 }
1837
1838 if (tbl_idx >= IPA_MEM_PART(v4_modem_rt_index_lo) &&
1839 tbl_idx <= IPA_MEM_PART(v4_modem_rt_index_hi)) {
1840 IPAERR("cannot configure modem v4 rt tuple by AP\n");
1841 return -EINVAL;
1842 }
1843
1844 if (tbl_idx >= IPA_MEM_PART(v6_modem_rt_index_lo) &&
1845 tbl_idx <= IPA_MEM_PART(v6_modem_rt_index_hi)) {
1846 IPAERR("cannot configure modem v6 rt tuple by AP\n");
1847 return -EINVAL;
1848 }
1849
1850 ipahal_read_reg_n_fields(IPA_ENDP_FILTER_ROUTER_HSH_CFG_n,
1851 tbl_idx, &fltrt_tuple);
1852 fltrt_tuple.rt = *tuple;
1853 ipahal_write_reg_n_fields(IPA_ENDP_FILTER_ROUTER_HSH_CFG_n,
1854 tbl_idx, &fltrt_tuple);
1855
1856 return 0;
1857}
1858
1859/**
1860 * ipa3_rt_read_tbl_from_hw() -Read routing table from IPA HW
1861 * @tbl_idx: routing table index
1862 * @ip_type: IPv4 or IPv6 table
1863 * @hashable: hashable or non-hashable table
1864 * @entry: array to fill the table entries
1865 * @num_entry: number of entries in entry array. set by the caller to indicate
1866 * entry array size. Then set by this function as an output parameter to
1867 * indicate the number of entries in the array
1868 *
1869 * This function reads the routing table from IPA SRAM and prepares an array
1870 * of entries. This function is mainly used for debugging purposes.
1871 *
1872 * If empty table or Modem Apps table, zero entries will be returned.
1873 *
1874 * Returns: 0 on success, negative on failure
1875 */
1876int ipa3_rt_read_tbl_from_hw(u32 tbl_idx, enum ipa_ip_type ip_type,
1877 bool hashable, struct ipahal_rt_rule_entry entry[], int *num_entry)
1878{
1879 void *ipa_sram_mmio;
1880 u64 hdr_base_ofst;
1881 int res = 0;
1882 u64 tbl_addr;
1883 bool is_sys;
1884 struct ipa_mem_buffer *sys_tbl_mem;
1885 u8 *rule_addr;
1886 int rule_idx;
1887
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001888 IPADBG_LOW("tbl_idx=%d ip_t=%d hashable=%d entry=0x%p num_entry=0x%p\n",
Amir Levy9659e592016-10-27 18:08:27 +03001889 tbl_idx, ip_type, hashable, entry, num_entry);
1890
1891 if (ip_type == IPA_IP_v4 && tbl_idx >= IPA_MEM_PART(v4_rt_num_index)) {
1892 IPAERR("Invalid params\n");
1893 return -EFAULT;
1894 }
1895
1896 if (ip_type == IPA_IP_v6 && tbl_idx >= IPA_MEM_PART(v6_rt_num_index)) {
1897 IPAERR("Invalid params\n");
1898 return -EFAULT;
1899 }
1900
1901 /* map IPA SRAM */
1902 ipa_sram_mmio = ioremap(ipa3_ctx->ipa_wrapper_base +
1903 ipa3_ctx->ctrl->ipa_reg_base_ofst +
1904 ipahal_get_reg_n_ofst(IPA_SRAM_DIRECT_ACCESS_n,
1905 ipa3_ctx->smem_restricted_bytes / 4),
1906 ipa3_ctx->smem_sz);
1907 if (!ipa_sram_mmio) {
1908 IPAERR("fail to ioremap IPA SRAM\n");
1909 return -ENOMEM;
1910 }
1911
1912 memset(entry, 0, sizeof(*entry) * (*num_entry));
1913 if (hashable) {
1914 if (ip_type == IPA_IP_v4)
1915 hdr_base_ofst =
1916 IPA_MEM_PART(v4_rt_hash_ofst);
1917 else
1918 hdr_base_ofst =
1919 IPA_MEM_PART(v6_rt_hash_ofst);
1920 } else {
1921 if (ip_type == IPA_IP_v4)
1922 hdr_base_ofst =
1923 IPA_MEM_PART(v4_rt_nhash_ofst);
1924 else
1925 hdr_base_ofst =
1926 IPA_MEM_PART(v6_rt_nhash_ofst);
1927 }
1928
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001929 IPADBG_LOW("hdr_base_ofst=0x%llx\n", hdr_base_ofst);
Amir Levy9659e592016-10-27 18:08:27 +03001930
1931 res = ipahal_fltrt_read_addr_from_hdr(ipa_sram_mmio + hdr_base_ofst,
1932 tbl_idx, &tbl_addr, &is_sys);
1933 if (res) {
1934 IPAERR("failed to read table address from header structure\n");
1935 goto bail;
1936 }
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001937 IPADBG_LOW("rt tbl %d: tbl_addr=0x%llx is_sys=%d\n",
Amir Levy9659e592016-10-27 18:08:27 +03001938 tbl_idx, tbl_addr, is_sys);
1939 if (!tbl_addr) {
1940 IPAERR("invalid rt tbl addr\n");
1941 res = -EFAULT;
1942 goto bail;
1943 }
1944
1945 /* for tables which reside in DDR access it from the virtual memory */
1946 if (is_sys) {
1947 struct ipa3_rt_tbl_set *set;
1948 struct ipa3_rt_tbl *tbl;
1949
1950 set = &ipa3_ctx->rt_tbl_set[ip_type];
1951 rule_addr = NULL;
1952 list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
1953 if (tbl->idx == tbl_idx) {
1954 sys_tbl_mem = &(tbl->curr_mem[hashable ?
1955 IPA_RULE_HASHABLE :
1956 IPA_RULE_NON_HASHABLE]);
1957 if (sys_tbl_mem->phys_base &&
1958 sys_tbl_mem->phys_base != tbl_addr) {
1959 IPAERR("mismatch:parsed=%llx sw=%pad\n"
1960 , tbl_addr,
1961 &sys_tbl_mem->phys_base);
1962 }
1963 if (sys_tbl_mem->phys_base)
1964 rule_addr = sys_tbl_mem->base;
1965 else
1966 rule_addr = NULL;
1967 }
1968 }
1969 } else {
1970 rule_addr = ipa_sram_mmio + hdr_base_ofst + tbl_addr;
1971 }
1972
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001973 IPADBG_LOW("First rule addr 0x%p\n", rule_addr);
Amir Levy9659e592016-10-27 18:08:27 +03001974
1975 if (!rule_addr) {
1976 /* Modem table in system memory or empty table */
1977 *num_entry = 0;
1978 goto bail;
1979 }
1980
1981 rule_idx = 0;
1982 while (rule_idx < *num_entry) {
1983 res = ipahal_rt_parse_hw_rule(rule_addr, &entry[rule_idx]);
1984 if (res) {
1985 IPAERR("failed parsing rt rule\n");
1986 goto bail;
1987 }
1988
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001989 IPADBG_LOW("rule_size=%d\n", entry[rule_idx].rule_size);
Amir Levy9659e592016-10-27 18:08:27 +03001990 if (!entry[rule_idx].rule_size)
1991 break;
1992
1993 rule_addr += entry[rule_idx].rule_size;
1994 rule_idx++;
1995 }
1996 *num_entry = rule_idx;
1997bail:
1998 iounmap(ipa_sram_mmio);
1999 return res;
2000}