blob: 41965398792a4379d61c63209c289f5ad33c53ae [file] [log] [blame]
Skylar Chang68c37d82018-04-07 16:42:36 -07001/* 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 "ipa_i.h"
14#include "ipahal/ipahal.h"
15
Skylar Chang7fa22712017-04-03 18:29:21 -070016static const u32 ipa_hdr_bin_sz[IPA_HDR_BIN_MAX] = { 8, 16, 24, 36, 64};
Amir Levy9659e592016-10-27 18:08:27 +030017static const u32 ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN_MAX] = { 32, 64};
18
19#define HDR_TYPE_IS_VALID(type) \
20 ((type) >= 0 && (type) < IPA_HDR_L2_MAX)
21
22#define HDR_PROC_TYPE_IS_VALID(type) \
23 ((type) >= 0 && (type) < IPA_HDR_PROC_MAX)
24
25/**
26 * ipa3_generate_hdr_hw_tbl() - generates the headers table
27 * @mem: [out] buffer to put the header table
28 *
29 * Returns: 0 on success, negative on failure
30 */
31static int ipa3_generate_hdr_hw_tbl(struct ipa_mem_buffer *mem)
32{
33 struct ipa3_hdr_entry *entry;
34
35 mem->size = ipa3_ctx->hdr_tbl.end;
36
37 if (mem->size == 0) {
38 IPAERR("hdr tbl empty\n");
39 return -EPERM;
40 }
41 IPADBG_LOW("tbl_sz=%d\n", ipa3_ctx->hdr_tbl.end);
42
43 mem->base = dma_alloc_coherent(ipa3_ctx->pdev, mem->size,
44 &mem->phys_base, GFP_KERNEL);
45 if (!mem->base) {
46 IPAERR("fail to alloc DMA buff of size %d\n", mem->size);
47 return -ENOMEM;
48 }
49
50 memset(mem->base, 0, mem->size);
51 list_for_each_entry(entry, &ipa3_ctx->hdr_tbl.head_hdr_entry_list,
52 link) {
53 if (entry->is_hdr_proc_ctx)
54 continue;
55 IPADBG_LOW("hdr of len %d ofst=%d\n", entry->hdr_len,
56 entry->offset_entry->offset);
57 ipahal_cp_hdr_to_hw_buff(mem->base, entry->offset_entry->offset,
58 entry->hdr, entry->hdr_len);
59 }
60
61 return 0;
62}
63
64static int ipa3_hdr_proc_ctx_to_hw_format(struct ipa_mem_buffer *mem,
65 u32 hdr_base_addr)
66{
67 struct ipa3_hdr_proc_ctx_entry *entry;
68 int ret;
Shihuan Liufe2818b2017-07-03 22:14:55 -070069 int ep;
Amir Levy9659e592016-10-27 18:08:27 +030070
71 list_for_each_entry(entry,
72 &ipa3_ctx->hdr_proc_ctx_tbl.head_proc_ctx_entry_list,
73 link) {
74 IPADBG_LOW("processing type %d ofst=%d\n",
75 entry->type, entry->offset_entry->offset);
Shihuan Liufe2818b2017-07-03 22:14:55 -070076
77 if (entry->l2tp_params.is_dst_pipe_valid) {
78 ep = ipa3_get_ep_mapping(entry->l2tp_params.dst_pipe);
79 if (ep >= 0) {
80 entry->l2tp_params.hdr_remove_param.
81 hdr_ofst_pkt_size_valid = ipa3_ctx->
82 ep[ep].cfg.hdr.hdr_ofst_pkt_size_valid;
83 entry->l2tp_params.hdr_remove_param.
84 hdr_ofst_pkt_size = ipa3_ctx->ep[ep].
85 cfg.hdr.hdr_ofst_pkt_size;
86 entry->l2tp_params.hdr_remove_param.
87 hdr_endianness = ipa3_ctx->ep[ep].
88 cfg.hdr_ext.hdr_little_endian ? 0 : 1;
89 }
90 }
91
Amir Levy9659e592016-10-27 18:08:27 +030092 ret = ipahal_cp_proc_ctx_to_hw_buff(entry->type, mem->base,
93 entry->offset_entry->offset,
94 entry->hdr->hdr_len,
95 entry->hdr->is_hdr_proc_ctx,
96 entry->hdr->phys_base,
97 hdr_base_addr,
Skylar Chang7fa22712017-04-03 18:29:21 -070098 entry->hdr->offset_entry,
99 entry->l2tp_params);
Amir Levy9659e592016-10-27 18:08:27 +0300100 if (ret)
101 return ret;
102 }
103
104 return 0;
105}
106
107/**
108 * ipa3_generate_hdr_proc_ctx_hw_tbl() -
109 * generates the headers processing context table.
110 * @mem: [out] buffer to put the processing context table
111 * @aligned_mem: [out] actual processing context table (with alignment).
112 * Processing context table needs to be 8 Bytes aligned.
113 *
114 * Returns: 0 on success, negative on failure
115 */
116static int ipa3_generate_hdr_proc_ctx_hw_tbl(u32 hdr_sys_addr,
117 struct ipa_mem_buffer *mem, struct ipa_mem_buffer *aligned_mem)
118{
119 u32 hdr_base_addr;
120
121 mem->size = (ipa3_ctx->hdr_proc_ctx_tbl.end) ? : 4;
122
123 /* make sure table is aligned */
124 mem->size += IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE;
125
126 IPADBG_LOW("tbl_sz=%d\n", ipa3_ctx->hdr_proc_ctx_tbl.end);
127
128 mem->base = dma_alloc_coherent(ipa3_ctx->pdev, mem->size,
129 &mem->phys_base, GFP_KERNEL);
130 if (!mem->base) {
131 IPAERR("fail to alloc DMA buff of size %d\n", mem->size);
132 return -ENOMEM;
133 }
134
135 aligned_mem->phys_base =
136 IPA_HDR_PROC_CTX_TABLE_ALIGNMENT(mem->phys_base);
137 aligned_mem->base = mem->base +
138 (aligned_mem->phys_base - mem->phys_base);
139 aligned_mem->size = mem->size - IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE;
140 memset(aligned_mem->base, 0, aligned_mem->size);
141 hdr_base_addr = (ipa3_ctx->hdr_tbl_lcl) ? IPA_MEM_PART(apps_hdr_ofst) :
142 hdr_sys_addr;
143 return ipa3_hdr_proc_ctx_to_hw_format(aligned_mem, hdr_base_addr);
144}
145
146/**
147 * __ipa_commit_hdr_v3_0() - Commits the header table from memory to HW
148 *
149 * Returns: 0 on success, negative on failure
150 */
151int __ipa_commit_hdr_v3_0(void)
152{
153 struct ipa3_desc desc[2];
154 struct ipa_mem_buffer hdr_mem;
155 struct ipa_mem_buffer ctx_mem;
156 struct ipa_mem_buffer aligned_ctx_mem;
157 struct ipahal_imm_cmd_dma_shared_mem dma_cmd_hdr = {0};
158 struct ipahal_imm_cmd_dma_shared_mem dma_cmd_ctx = {0};
159 struct ipahal_imm_cmd_register_write reg_write_cmd = {0};
160 struct ipahal_imm_cmd_hdr_init_system hdr_init_cmd = {0};
161 struct ipahal_imm_cmd_pyld *hdr_cmd_pyld = NULL;
162 struct ipahal_imm_cmd_pyld *ctx_cmd_pyld = NULL;
163 int rc = -EFAULT;
164 u32 proc_ctx_size;
165 u32 proc_ctx_ofst;
166 u32 proc_ctx_size_ddr;
167
168 memset(desc, 0, 2 * sizeof(struct ipa3_desc));
169
170 if (ipa3_generate_hdr_hw_tbl(&hdr_mem)) {
171 IPAERR("fail to generate HDR HW TBL\n");
172 goto end;
173 }
174
175 if (ipa3_generate_hdr_proc_ctx_hw_tbl(hdr_mem.phys_base, &ctx_mem,
176 &aligned_ctx_mem)) {
177 IPAERR("fail to generate HDR PROC CTX HW TBL\n");
178 goto end;
179 }
180
181 if (ipa3_ctx->hdr_tbl_lcl) {
182 if (hdr_mem.size > IPA_MEM_PART(apps_hdr_size)) {
183 IPAERR("tbl too big needed %d avail %d\n", hdr_mem.size,
184 IPA_MEM_PART(apps_hdr_size));
185 goto end;
186 } else {
187 dma_cmd_hdr.is_read = false; /* write operation */
188 dma_cmd_hdr.skip_pipeline_clear = false;
189 dma_cmd_hdr.pipeline_clear_options = IPAHAL_HPS_CLEAR;
190 dma_cmd_hdr.system_addr = hdr_mem.phys_base;
191 dma_cmd_hdr.size = hdr_mem.size;
192 dma_cmd_hdr.local_addr =
193 ipa3_ctx->smem_restricted_bytes +
194 IPA_MEM_PART(apps_hdr_ofst);
195 hdr_cmd_pyld = ipahal_construct_imm_cmd(
196 IPA_IMM_CMD_DMA_SHARED_MEM,
197 &dma_cmd_hdr, false);
198 if (!hdr_cmd_pyld) {
199 IPAERR("fail construct dma_shared_mem cmd\n");
200 goto end;
201 }
Amir Levy9659e592016-10-27 18:08:27 +0300202 }
203 } else {
204 if (hdr_mem.size > IPA_MEM_PART(apps_hdr_size_ddr)) {
205 IPAERR("tbl too big needed %d avail %d\n", hdr_mem.size,
206 IPA_MEM_PART(apps_hdr_size_ddr));
207 goto end;
208 } else {
209 hdr_init_cmd.hdr_table_addr = hdr_mem.phys_base;
210 hdr_cmd_pyld = ipahal_construct_imm_cmd(
211 IPA_IMM_CMD_HDR_INIT_SYSTEM,
212 &hdr_init_cmd, false);
213 if (!hdr_cmd_pyld) {
214 IPAERR("fail construct hdr_init_system cmd\n");
215 goto end;
216 }
Amir Levy9659e592016-10-27 18:08:27 +0300217 }
218 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300219 ipa3_init_imm_cmd_desc(&desc[0], hdr_cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +0300220 IPA_DUMP_BUFF(hdr_mem.base, hdr_mem.phys_base, hdr_mem.size);
221
222 proc_ctx_size = IPA_MEM_PART(apps_hdr_proc_ctx_size);
223 proc_ctx_ofst = IPA_MEM_PART(apps_hdr_proc_ctx_ofst);
224 if (ipa3_ctx->hdr_proc_ctx_tbl_lcl) {
225 if (aligned_ctx_mem.size > proc_ctx_size) {
226 IPAERR("tbl too big needed %d avail %d\n",
227 aligned_ctx_mem.size,
228 proc_ctx_size);
229 goto end;
230 } else {
231 dma_cmd_ctx.is_read = false; /* Write operation */
232 dma_cmd_ctx.skip_pipeline_clear = false;
233 dma_cmd_ctx.pipeline_clear_options = IPAHAL_HPS_CLEAR;
234 dma_cmd_ctx.system_addr = aligned_ctx_mem.phys_base;
235 dma_cmd_ctx.size = aligned_ctx_mem.size;
236 dma_cmd_ctx.local_addr =
237 ipa3_ctx->smem_restricted_bytes +
238 proc_ctx_ofst;
239 ctx_cmd_pyld = ipahal_construct_imm_cmd(
240 IPA_IMM_CMD_DMA_SHARED_MEM,
241 &dma_cmd_ctx, false);
242 if (!ctx_cmd_pyld) {
243 IPAERR("fail construct dma_shared_mem cmd\n");
244 goto end;
245 }
Amir Levy9659e592016-10-27 18:08:27 +0300246 }
247 } else {
248 proc_ctx_size_ddr = IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr);
249 if (aligned_ctx_mem.size > proc_ctx_size_ddr) {
250 IPAERR("tbl too big, needed %d avail %d\n",
251 aligned_ctx_mem.size,
252 proc_ctx_size_ddr);
253 goto end;
254 } else {
255 reg_write_cmd.skip_pipeline_clear = false;
256 reg_write_cmd.pipeline_clear_options =
257 IPAHAL_HPS_CLEAR;
258 reg_write_cmd.offset =
259 ipahal_get_reg_ofst(
260 IPA_SYS_PKT_PROC_CNTXT_BASE);
261 reg_write_cmd.value = aligned_ctx_mem.phys_base;
262 reg_write_cmd.value_mask =
263 ~(IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE - 1);
264 ctx_cmd_pyld = ipahal_construct_imm_cmd(
265 IPA_IMM_CMD_REGISTER_WRITE,
266 &reg_write_cmd, false);
267 if (!ctx_cmd_pyld) {
268 IPAERR("fail construct register_write cmd\n");
269 goto end;
270 }
Amir Levy9659e592016-10-27 18:08:27 +0300271 }
272 }
Amir Levy479cfdd2017-10-26 12:23:14 +0300273 ipa3_init_imm_cmd_desc(&desc[1], ctx_cmd_pyld);
Amir Levy9659e592016-10-27 18:08:27 +0300274 IPA_DUMP_BUFF(ctx_mem.base, ctx_mem.phys_base, ctx_mem.size);
275
276 if (ipa3_send_cmd(2, desc))
277 IPAERR("fail to send immediate command\n");
278 else
279 rc = 0;
280
281 if (ipa3_ctx->hdr_tbl_lcl) {
282 dma_free_coherent(ipa3_ctx->pdev, hdr_mem.size, hdr_mem.base,
283 hdr_mem.phys_base);
284 } else {
285 if (!rc) {
286 if (ipa3_ctx->hdr_mem.phys_base)
287 dma_free_coherent(ipa3_ctx->pdev,
288 ipa3_ctx->hdr_mem.size,
289 ipa3_ctx->hdr_mem.base,
290 ipa3_ctx->hdr_mem.phys_base);
291 ipa3_ctx->hdr_mem = hdr_mem;
292 }
293 }
294
295 if (ipa3_ctx->hdr_proc_ctx_tbl_lcl) {
296 dma_free_coherent(ipa3_ctx->pdev, ctx_mem.size, ctx_mem.base,
297 ctx_mem.phys_base);
298 } else {
299 if (!rc) {
300 if (ipa3_ctx->hdr_proc_ctx_mem.phys_base)
301 dma_free_coherent(ipa3_ctx->pdev,
302 ipa3_ctx->hdr_proc_ctx_mem.size,
303 ipa3_ctx->hdr_proc_ctx_mem.base,
304 ipa3_ctx->hdr_proc_ctx_mem.phys_base);
305 ipa3_ctx->hdr_proc_ctx_mem = ctx_mem;
306 }
307 }
308
309end:
310 if (ctx_cmd_pyld)
311 ipahal_destroy_imm_cmd(ctx_cmd_pyld);
312
313 if (hdr_cmd_pyld)
314 ipahal_destroy_imm_cmd(hdr_cmd_pyld);
315
316 return rc;
317}
318
319static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
Skylar Chang68c37d82018-04-07 16:42:36 -0700320 bool add_ref_hdr, bool user_only)
Amir Levy9659e592016-10-27 18:08:27 +0300321{
322 struct ipa3_hdr_entry *hdr_entry;
323 struct ipa3_hdr_proc_ctx_entry *entry;
324 struct ipa3_hdr_proc_ctx_offset_entry *offset;
325 u32 bin;
326 struct ipa3_hdr_proc_ctx_tbl *htbl = &ipa3_ctx->hdr_proc_ctx_tbl;
327 int id;
328 int needed_len;
329 int mem_size;
330
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200331 IPADBG_LOW("Add processing type %d hdr_hdl %d\n",
Amir Levy9659e592016-10-27 18:08:27 +0300332 proc_ctx->type, proc_ctx->hdr_hdl);
333
334 if (!HDR_PROC_TYPE_IS_VALID(proc_ctx->type)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530335 IPAERR_RL("invalid processing type %d\n", proc_ctx->type);
Amir Levy9659e592016-10-27 18:08:27 +0300336 return -EINVAL;
337 }
338
339 hdr_entry = ipa3_id_find(proc_ctx->hdr_hdl);
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200340 if (!hdr_entry) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530341 IPAERR_RL("hdr_hdl is invalid\n");
Amir Levy9659e592016-10-27 18:08:27 +0300342 return -EINVAL;
343 }
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530344 if (hdr_entry->cookie != IPA_HDR_COOKIE) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530345 IPAERR_RL("Invalid header cookie %u\n", hdr_entry->cookie);
Mohammed Javida4252d82017-10-13 13:51:21 +0530346 WARN_ON_RATELIMIT_IPA(1);
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200347 return -EINVAL;
348 }
349 IPADBG("Associated header is name=%s is_hdr_proc_ctx=%d\n",
350 hdr_entry->name, hdr_entry->is_hdr_proc_ctx);
Amir Levy9659e592016-10-27 18:08:27 +0300351
352 entry = kmem_cache_zalloc(ipa3_ctx->hdr_proc_ctx_cache, GFP_KERNEL);
353 if (!entry) {
354 IPAERR("failed to alloc proc_ctx object\n");
355 return -ENOMEM;
356 }
357
358 INIT_LIST_HEAD(&entry->link);
359
360 entry->type = proc_ctx->type;
361 entry->hdr = hdr_entry;
Skylar Chang7fa22712017-04-03 18:29:21 -0700362 entry->l2tp_params = proc_ctx->l2tp_params;
Amir Levy9659e592016-10-27 18:08:27 +0300363 if (add_ref_hdr)
364 hdr_entry->ref_cnt++;
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530365 entry->cookie = IPA_PROC_HDR_COOKIE;
Skylar Chang68c37d82018-04-07 16:42:36 -0700366 entry->ipacm_installed = user_only;
Amir Levy9659e592016-10-27 18:08:27 +0300367
368 needed_len = ipahal_get_proc_ctx_needed_len(proc_ctx->type);
369
370 if (needed_len <= ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN0]) {
371 bin = IPA_HDR_PROC_CTX_BIN0;
372 } else if (needed_len <=
373 ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN1]) {
374 bin = IPA_HDR_PROC_CTX_BIN1;
375 } else {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530376 IPAERR_RL("unexpected needed len %d\n", needed_len);
Mohammed Javida4252d82017-10-13 13:51:21 +0530377 WARN_ON_RATELIMIT_IPA(1);
Amir Levy9659e592016-10-27 18:08:27 +0300378 goto bad_len;
379 }
380
381 mem_size = (ipa3_ctx->hdr_proc_ctx_tbl_lcl) ?
382 IPA_MEM_PART(apps_hdr_proc_ctx_size) :
383 IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr);
Amir Levy9659e592016-10-27 18:08:27 +0300384 if (list_empty(&htbl->head_free_offset_list[bin])) {
Skylar Changd8b80fe2017-06-08 15:47:22 -0700385 if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530386 IPAERR_RL("hdr proc ctx table overflow\n");
Skylar Changd8b80fe2017-06-08 15:47:22 -0700387 goto bad_len;
388 }
389
Amir Levy9659e592016-10-27 18:08:27 +0300390 offset = kmem_cache_zalloc(ipa3_ctx->hdr_proc_ctx_offset_cache,
391 GFP_KERNEL);
392 if (!offset) {
393 IPAERR("failed to alloc offset object\n");
394 goto bad_len;
395 }
396 INIT_LIST_HEAD(&offset->link);
397 /*
398 * for a first item grow, set the bin and offset which are set
399 * in stone
400 */
401 offset->offset = htbl->end;
402 offset->bin = bin;
Skylar Chang68c37d82018-04-07 16:42:36 -0700403 offset->ipacm_installed = user_only;
Amir Levy9659e592016-10-27 18:08:27 +0300404 htbl->end += ipa_hdr_proc_ctx_bin_sz[bin];
405 list_add(&offset->link,
406 &htbl->head_offset_list[bin]);
407 } else {
408 /* get the first free slot */
409 offset =
410 list_first_entry(&htbl->head_free_offset_list[bin],
411 struct ipa3_hdr_proc_ctx_offset_entry, link);
Skylar Chang68c37d82018-04-07 16:42:36 -0700412 offset->ipacm_installed = user_only;
Amir Levy9659e592016-10-27 18:08:27 +0300413 list_move(&offset->link, &htbl->head_offset_list[bin]);
414 }
415
416 entry->offset_entry = offset;
417 list_add(&entry->link, &htbl->head_proc_ctx_entry_list);
418 htbl->proc_ctx_cnt++;
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200419 IPADBG("add proc ctx of sz=%d cnt=%d ofst=%d\n", needed_len,
Amir Levy9659e592016-10-27 18:08:27 +0300420 htbl->proc_ctx_cnt, offset->offset);
421
422 id = ipa3_id_alloc(entry);
423 if (id < 0) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530424 IPAERR_RL("failed to alloc id\n");
425 WARN_ON_RATELIMIT_IPA(1);
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530426 goto ipa_insert_failed;
Amir Levy9659e592016-10-27 18:08:27 +0300427 }
428 entry->id = id;
429 proc_ctx->proc_ctx_hdl = id;
430 entry->ref_cnt++;
431
432 return 0;
433
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530434ipa_insert_failed:
Mohammed Javid42ad67b2017-07-27 15:12:18 +0530435 list_move(&offset->link,
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530436 &htbl->head_free_offset_list[offset->bin]);
437 entry->offset_entry = NULL;
438 list_del(&entry->link);
439 htbl->proc_ctx_cnt--;
440
Amir Levy9659e592016-10-27 18:08:27 +0300441bad_len:
442 if (add_ref_hdr)
443 hdr_entry->ref_cnt--;
444 entry->cookie = 0;
445 kmem_cache_free(ipa3_ctx->hdr_proc_ctx_cache, entry);
446 return -EPERM;
447}
448
449
Skylar Chang68c37d82018-04-07 16:42:36 -0700450static int __ipa_add_hdr(struct ipa_hdr_add *hdr, bool user)
Amir Levy9659e592016-10-27 18:08:27 +0300451{
452 struct ipa3_hdr_entry *entry;
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530453 struct ipa_hdr_offset_entry *offset = NULL;
Amir Levy9659e592016-10-27 18:08:27 +0300454 u32 bin;
455 struct ipa3_hdr_tbl *htbl = &ipa3_ctx->hdr_tbl;
456 int id;
457 int mem_size;
458
459 if (hdr->hdr_len == 0 || hdr->hdr_len > IPA_HDR_MAX_SIZE) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530460 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +0300461 goto error;
462 }
463
464 if (!HDR_TYPE_IS_VALID(hdr->type)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530465 IPAERR_RL("invalid hdr type %d\n", hdr->type);
Amir Levy9659e592016-10-27 18:08:27 +0300466 goto error;
467 }
468
469 entry = kmem_cache_zalloc(ipa3_ctx->hdr_cache, GFP_KERNEL);
470 if (!entry) {
471 IPAERR("failed to alloc hdr object\n");
472 goto error;
473 }
474
475 INIT_LIST_HEAD(&entry->link);
476
477 memcpy(entry->hdr, hdr->hdr, hdr->hdr_len);
478 entry->hdr_len = hdr->hdr_len;
479 strlcpy(entry->name, hdr->name, IPA_RESOURCE_NAME_MAX);
480 entry->is_partial = hdr->is_partial;
481 entry->type = hdr->type;
482 entry->is_eth2_ofst_valid = hdr->is_eth2_ofst_valid;
483 entry->eth2_ofst = hdr->eth2_ofst;
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530484 entry->cookie = IPA_HDR_COOKIE;
Skylar Chang68c37d82018-04-07 16:42:36 -0700485 entry->ipacm_installed = user;
Amir Levy9659e592016-10-27 18:08:27 +0300486
487 if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN0])
488 bin = IPA_HDR_BIN0;
489 else if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN1])
490 bin = IPA_HDR_BIN1;
491 else if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN2])
492 bin = IPA_HDR_BIN2;
493 else if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN3])
494 bin = IPA_HDR_BIN3;
495 else if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN4])
496 bin = IPA_HDR_BIN4;
497 else {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530498 IPAERR_RL("unexpected hdr len %d\n", hdr->hdr_len);
Amir Levy9659e592016-10-27 18:08:27 +0300499 goto bad_hdr_len;
500 }
501
502 mem_size = (ipa3_ctx->hdr_tbl_lcl) ? IPA_MEM_PART(apps_hdr_size) :
503 IPA_MEM_PART(apps_hdr_size_ddr);
504
Skylar Changd8b80fe2017-06-08 15:47:22 -0700505 if (list_empty(&htbl->head_free_offset_list[bin])) {
506 /* if header does not fit to table, place it in DDR */
507 if (htbl->end + ipa_hdr_bin_sz[bin] > mem_size) {
508 entry->is_hdr_proc_ctx = true;
509 entry->phys_base = dma_map_single(ipa3_ctx->pdev,
510 entry->hdr,
511 entry->hdr_len,
512 DMA_TO_DEVICE);
513 if (dma_mapping_error(ipa3_ctx->pdev,
514 entry->phys_base)) {
515 IPAERR("dma_map_single failure for entry\n");
516 goto fail_dma_mapping;
517 }
518 } else {
519 entry->is_hdr_proc_ctx = false;
Amir Levy9659e592016-10-27 18:08:27 +0300520 offset = kmem_cache_zalloc(ipa3_ctx->hdr_offset_cache,
521 GFP_KERNEL);
522 if (!offset) {
523 IPAERR("failed to alloc hdr offset object\n");
524 goto bad_hdr_len;
525 }
526 INIT_LIST_HEAD(&offset->link);
527 /*
528 * for a first item grow, set the bin and offset which
529 * are set in stone
530 */
531 offset->offset = htbl->end;
532 offset->bin = bin;
533 htbl->end += ipa_hdr_bin_sz[bin];
534 list_add(&offset->link,
535 &htbl->head_offset_list[bin]);
Skylar Changd8b80fe2017-06-08 15:47:22 -0700536 entry->offset_entry = offset;
Skylar Chang68c37d82018-04-07 16:42:36 -0700537 offset->ipacm_installed = user;
Amir Levy9659e592016-10-27 18:08:27 +0300538 }
Skylar Changd8b80fe2017-06-08 15:47:22 -0700539 } else {
540 entry->is_hdr_proc_ctx = false;
541 /* get the first free slot */
542 offset = list_first_entry(&htbl->head_free_offset_list[bin],
543 struct ipa_hdr_offset_entry, link);
544 list_move(&offset->link, &htbl->head_offset_list[bin]);
Amir Levy9659e592016-10-27 18:08:27 +0300545 entry->offset_entry = offset;
Skylar Chang68c37d82018-04-07 16:42:36 -0700546 offset->ipacm_installed = user;
Amir Levy9659e592016-10-27 18:08:27 +0300547 }
548
549 list_add(&entry->link, &htbl->head_hdr_entry_list);
550 htbl->hdr_cnt++;
551 if (entry->is_hdr_proc_ctx)
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200552 IPADBG("add hdr of sz=%d hdr_cnt=%d phys_base=%pa\n",
Amir Levy9659e592016-10-27 18:08:27 +0300553 hdr->hdr_len,
554 htbl->hdr_cnt,
555 &entry->phys_base);
556 else
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200557 IPADBG("add hdr of sz=%d hdr_cnt=%d ofst=%d\n",
Amir Levy9659e592016-10-27 18:08:27 +0300558 hdr->hdr_len,
559 htbl->hdr_cnt,
560 entry->offset_entry->offset);
561
562 id = ipa3_id_alloc(entry);
563 if (id < 0) {
Mohammed Javida4252d82017-10-13 13:51:21 +0530564 IPAERR_RL("failed to alloc id\n");
565 WARN_ON_RATELIMIT_IPA(1);
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530566 goto ipa_insert_failed;
Amir Levy9659e592016-10-27 18:08:27 +0300567 }
568 entry->id = id;
569 hdr->hdr_hdl = id;
570 entry->ref_cnt++;
571
572 if (entry->is_hdr_proc_ctx) {
573 struct ipa_hdr_proc_ctx_add proc_ctx;
574
575 IPADBG("adding processing context for header %s\n", hdr->name);
576 proc_ctx.type = IPA_HDR_PROC_NONE;
577 proc_ctx.hdr_hdl = id;
Skylar Chang68c37d82018-04-07 16:42:36 -0700578 if (__ipa_add_hdr_proc_ctx(&proc_ctx, false, user)) {
Amir Levy9659e592016-10-27 18:08:27 +0300579 IPAERR("failed to add hdr proc ctx\n");
580 goto fail_add_proc_ctx;
581 }
582 entry->proc_ctx = ipa3_id_find(proc_ctx.proc_ctx_hdl);
583 }
584
585 return 0;
586
587fail_add_proc_ctx:
588 entry->ref_cnt--;
589 hdr->hdr_hdl = 0;
590 ipa3_id_remove(id);
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530591ipa_insert_failed:
592 if (entry->is_hdr_proc_ctx) {
593 dma_unmap_single(ipa3_ctx->pdev, entry->phys_base,
594 entry->hdr_len, DMA_TO_DEVICE);
595 } else {
596 if (offset)
597 list_move(&offset->link,
598 &htbl->head_free_offset_list[offset->bin]);
599 entry->offset_entry = NULL;
600 }
Amir Levy9659e592016-10-27 18:08:27 +0300601 htbl->hdr_cnt--;
602 list_del(&entry->link);
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530603
Utkarsh Saxenae4166a72017-05-22 13:21:55 +0530604fail_dma_mapping:
605 entry->is_hdr_proc_ctx = false;
606
Amir Levy9659e592016-10-27 18:08:27 +0300607bad_hdr_len:
608 entry->cookie = 0;
609 kmem_cache_free(ipa3_ctx->hdr_cache, entry);
610error:
611 return -EPERM;
612}
613
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200614static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl,
615 bool release_hdr, bool by_user)
Amir Levy9659e592016-10-27 18:08:27 +0300616{
617 struct ipa3_hdr_proc_ctx_entry *entry;
618 struct ipa3_hdr_proc_ctx_tbl *htbl = &ipa3_ctx->hdr_proc_ctx_tbl;
619
620 entry = ipa3_id_find(proc_ctx_hdl);
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530621 if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530622 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +0300623 return -EINVAL;
624 }
625
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200626 IPADBG("del proc ctx cnt=%d ofst=%d\n",
Amir Levy9659e592016-10-27 18:08:27 +0300627 htbl->proc_ctx_cnt, entry->offset_entry->offset);
628
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200629 if (by_user && entry->user_deleted) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530630 IPAERR_RL("proc_ctx already deleted by user\n");
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200631 return -EINVAL;
632 }
633
634 if (by_user)
635 entry->user_deleted = true;
636
Amir Levy9659e592016-10-27 18:08:27 +0300637 if (--entry->ref_cnt) {
638 IPADBG("proc_ctx_hdl %x ref_cnt %d\n",
639 proc_ctx_hdl, entry->ref_cnt);
640 return 0;
641 }
642
643 if (release_hdr)
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200644 __ipa3_del_hdr(entry->hdr->id, false);
Amir Levy9659e592016-10-27 18:08:27 +0300645
646 /* move the offset entry to appropriate free list */
647 list_move(&entry->offset_entry->link,
648 &htbl->head_free_offset_list[entry->offset_entry->bin]);
649 list_del(&entry->link);
650 htbl->proc_ctx_cnt--;
651 entry->cookie = 0;
652 kmem_cache_free(ipa3_ctx->hdr_proc_ctx_cache, entry);
653
654 /* remove the handle from the database */
655 ipa3_id_remove(proc_ctx_hdl);
656
657 return 0;
658}
659
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200660int __ipa3_del_hdr(u32 hdr_hdl, bool by_user)
Amir Levy9659e592016-10-27 18:08:27 +0300661{
662 struct ipa3_hdr_entry *entry;
663 struct ipa3_hdr_tbl *htbl = &ipa3_ctx->hdr_tbl;
664
665 entry = ipa3_id_find(hdr_hdl);
666 if (entry == NULL) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530667 IPAERR_RL("lookup failed\n");
Amir Levy9659e592016-10-27 18:08:27 +0300668 return -EINVAL;
669 }
670
Mohammed Javid93e94ce2017-06-15 15:39:04 +0530671 if (entry->cookie != IPA_HDR_COOKIE) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530672 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +0300673 return -EINVAL;
674 }
675
676 if (entry->is_hdr_proc_ctx)
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200677 IPADBG("del hdr of len=%d hdr_cnt=%d phys_base=%pa\n",
Amir Levy9659e592016-10-27 18:08:27 +0300678 entry->hdr_len, htbl->hdr_cnt, &entry->phys_base);
679 else
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200680 IPADBG("del hdr of len=%d hdr_cnt=%d ofst=%d\n",
681 entry->hdr_len, htbl->hdr_cnt,
682 entry->offset_entry->offset);
Amir Levy9659e592016-10-27 18:08:27 +0300683
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200684 if (by_user && entry->user_deleted) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530685 IPAERR_RL("proc_ctx already deleted by user\n");
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200686 return -EINVAL;
687 }
688
Ghanim Fodi3be117a2017-12-19 19:15:19 +0200689 if (by_user) {
690 if (!strcmp(entry->name, IPA_LAN_RX_HDR_NAME)) {
691 IPADBG("Trying to delete hdr %s offset=%u\n",
692 entry->name, entry->offset_entry->offset);
693 if (!entry->offset_entry->offset) {
694 IPAERR("User cannot delete default header\n");
695 return -EPERM;
696 }
697 }
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200698 entry->user_deleted = true;
Ghanim Fodi3be117a2017-12-19 19:15:19 +0200699 }
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200700
Amir Levy9659e592016-10-27 18:08:27 +0300701 if (--entry->ref_cnt) {
702 IPADBG("hdr_hdl %x ref_cnt %d\n", hdr_hdl, entry->ref_cnt);
703 return 0;
704 }
705
706 if (entry->is_hdr_proc_ctx) {
707 dma_unmap_single(ipa3_ctx->pdev,
708 entry->phys_base,
709 entry->hdr_len,
710 DMA_TO_DEVICE);
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200711 __ipa3_del_hdr_proc_ctx(entry->proc_ctx->id, false, false);
Amir Levy9659e592016-10-27 18:08:27 +0300712 } else {
713 /* move the offset entry to appropriate free list */
714 list_move(&entry->offset_entry->link,
715 &htbl->head_free_offset_list[entry->offset_entry->bin]);
716 }
717 list_del(&entry->link);
718 htbl->hdr_cnt--;
719 entry->cookie = 0;
720 kmem_cache_free(ipa3_ctx->hdr_cache, entry);
721
722 /* remove the handle from the database */
723 ipa3_id_remove(hdr_hdl);
724
725 return 0;
726}
727
728/**
729 * ipa3_add_hdr() - add the specified headers to SW and optionally commit them
730 * to IPA HW
731 * @hdrs: [inout] set of headers to add
732 *
733 * Returns: 0 on success, negative on failure
734 *
735 * Note: Should not be called from atomic context
736 */
737int ipa3_add_hdr(struct ipa_ioc_add_hdr *hdrs)
738{
Skylar Chang68c37d82018-04-07 16:42:36 -0700739 return ipa3_add_hdr_usr(hdrs, false);
740}
741
742/**
743 * ipa3_add_hdr_usr() - add the specified headers to SW
744 * and optionally commit them to IPA HW
745 * @hdrs: [inout] set of headers to add
746 * @user_only: [in] indicate installed from user
747 *
748 * Returns: 0 on success, negative on failure
749 *
750 * Note: Should not be called from atomic context
751 */
752int ipa3_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool user_only)
753{
Amir Levy9659e592016-10-27 18:08:27 +0300754 int i;
755 int result = -EFAULT;
756
757 if (hdrs == NULL || hdrs->num_hdrs == 0) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530758 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +0300759 return -EINVAL;
760 }
761
762 mutex_lock(&ipa3_ctx->lock);
763 IPADBG("adding %d headers to IPA driver internal data struct\n",
764 hdrs->num_hdrs);
765 for (i = 0; i < hdrs->num_hdrs; i++) {
Skylar Chang68c37d82018-04-07 16:42:36 -0700766 if (__ipa_add_hdr(&hdrs->hdr[i], user_only)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530767 IPAERR_RL("failed to add hdr %d\n", i);
Amir Levy9659e592016-10-27 18:08:27 +0300768 hdrs->hdr[i].status = -1;
769 } else {
770 hdrs->hdr[i].status = 0;
771 }
772 }
773
774 if (hdrs->commit) {
775 IPADBG("committing all headers to IPA core");
776 if (ipa3_ctx->ctrl->ipa3_commit_hdr()) {
777 result = -EPERM;
778 goto bail;
779 }
780 }
781 result = 0;
782bail:
783 mutex_unlock(&ipa3_ctx->lock);
784 return result;
785}
786
787/**
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200788 * ipa3_del_hdr_by_user() - Remove the specified headers
789 * from SW and optionally commit them to IPA HW
Amir Levy9659e592016-10-27 18:08:27 +0300790 * @hdls: [inout] set of headers to delete
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200791 * @by_user: Operation requested by user?
Amir Levy9659e592016-10-27 18:08:27 +0300792 *
793 * Returns: 0 on success, negative on failure
794 *
795 * Note: Should not be called from atomic context
796 */
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200797int ipa3_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user)
Amir Levy9659e592016-10-27 18:08:27 +0300798{
799 int i;
800 int result = -EFAULT;
801
802 if (hdls == NULL || hdls->num_hdls == 0) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530803 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +0300804 return -EINVAL;
805 }
806
807 mutex_lock(&ipa3_ctx->lock);
808 for (i = 0; i < hdls->num_hdls; i++) {
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200809 if (__ipa3_del_hdr(hdls->hdl[i].hdl, by_user)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530810 IPAERR_RL("failed to del hdr %i\n", i);
Amir Levy9659e592016-10-27 18:08:27 +0300811 hdls->hdl[i].status = -1;
812 } else {
813 hdls->hdl[i].status = 0;
814 }
815 }
816
817 if (hdls->commit) {
818 if (ipa3_ctx->ctrl->ipa3_commit_hdr()) {
819 result = -EPERM;
820 goto bail;
821 }
822 }
823 result = 0;
824bail:
825 mutex_unlock(&ipa3_ctx->lock);
826 return result;
827}
828
829/**
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200830 * ipa3_del_hdr() - Remove the specified headers from SW
831 * and optionally commit them to IPA HW
832 * @hdls: [inout] set of headers to delete
833 *
834 * Returns: 0 on success, negative on failure
835 *
836 * Note: Should not be called from atomic context
837 */
838int ipa3_del_hdr(struct ipa_ioc_del_hdr *hdls)
839{
840 return ipa3_del_hdr_by_user(hdls, false);
841}
842
843/**
Amir Levy9659e592016-10-27 18:08:27 +0300844 * ipa3_add_hdr_proc_ctx() - add the specified headers to SW
845 * and optionally commit them to IPA HW
846 * @proc_ctxs: [inout] set of processing context headers to add
Skylar Chang68c37d82018-04-07 16:42:36 -0700847 * @user_only: [in] indicate installed by user-space module
Amir Levy9659e592016-10-27 18:08:27 +0300848 *
849 * Returns: 0 on success, negative on failure
850 *
851 * Note: Should not be called from atomic context
852 */
Skylar Chang68c37d82018-04-07 16:42:36 -0700853int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs,
854 bool user_only)
Amir Levy9659e592016-10-27 18:08:27 +0300855{
856 int i;
857 int result = -EFAULT;
858
859 if (proc_ctxs == NULL || proc_ctxs->num_proc_ctxs == 0) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530860 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +0300861 return -EINVAL;
862 }
863
864 mutex_lock(&ipa3_ctx->lock);
865 IPADBG("adding %d header processing contextes to IPA driver\n",
866 proc_ctxs->num_proc_ctxs);
867 for (i = 0; i < proc_ctxs->num_proc_ctxs; i++) {
Skylar Chang68c37d82018-04-07 16:42:36 -0700868 if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i],
869 true, user_only)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530870 IPAERR_RL("failed to add hdr pric ctx %d\n", i);
Amir Levy9659e592016-10-27 18:08:27 +0300871 proc_ctxs->proc_ctx[i].status = -1;
872 } else {
873 proc_ctxs->proc_ctx[i].status = 0;
874 }
875 }
876
877 if (proc_ctxs->commit) {
878 IPADBG("committing all headers to IPA core");
879 if (ipa3_ctx->ctrl->ipa3_commit_hdr()) {
880 result = -EPERM;
881 goto bail;
882 }
883 }
884 result = 0;
885bail:
886 mutex_unlock(&ipa3_ctx->lock);
887 return result;
888}
889
890/**
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200891 * ipa3_del_hdr_proc_ctx_by_user() -
Amir Levy9659e592016-10-27 18:08:27 +0300892 * Remove the specified processing context headers from SW and
893 * optionally commit them to IPA HW.
894 * @hdls: [inout] set of processing context headers to delete
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200895 * @by_user: Operation requested by user?
Amir Levy9659e592016-10-27 18:08:27 +0300896 *
897 * Returns: 0 on success, negative on failure
898 *
899 * Note: Should not be called from atomic context
900 */
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200901int ipa3_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls,
902 bool by_user)
Amir Levy9659e592016-10-27 18:08:27 +0300903{
904 int i;
905 int result;
906
907 if (hdls == NULL || hdls->num_hdls == 0) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530908 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +0300909 return -EINVAL;
910 }
911
912 mutex_lock(&ipa3_ctx->lock);
913 for (i = 0; i < hdls->num_hdls; i++) {
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200914 if (__ipa3_del_hdr_proc_ctx(hdls->hdl[i].hdl, true, by_user)) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +0530915 IPAERR_RL("failed to del hdr %i\n", i);
Amir Levy9659e592016-10-27 18:08:27 +0300916 hdls->hdl[i].status = -1;
917 } else {
918 hdls->hdl[i].status = 0;
919 }
920 }
921
922 if (hdls->commit) {
923 if (ipa3_ctx->ctrl->ipa3_commit_hdr()) {
924 result = -EPERM;
925 goto bail;
926 }
927 }
928 result = 0;
929bail:
930 mutex_unlock(&ipa3_ctx->lock);
931 return result;
932}
933
934/**
Ghanim Fodi2c8ba072017-01-12 15:14:15 +0200935 * ipa3_del_hdr_proc_ctx() -
936 * Remove the specified processing context headers from SW and
937 * optionally commit them to IPA HW.
938 * @hdls: [inout] set of processing context headers to delete
939 *
940 * Returns: 0 on success, negative on failure
941 *
942 * Note: Should not be called from atomic context
943 */
944int ipa3_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)
945{
946 return ipa3_del_hdr_proc_ctx_by_user(hdls, false);
947}
948
949/**
Amir Levy9659e592016-10-27 18:08:27 +0300950 * ipa3_commit_hdr() - commit to IPA HW the current header table in SW
951 *
952 * Returns: 0 on success, negative on failure
953 *
954 * Note: Should not be called from atomic context
955 */
956int ipa3_commit_hdr(void)
957{
958 int result = -EFAULT;
959
960 /*
961 * issue a commit on the routing module since routing rules point to
962 * header table entries
963 */
964 if (ipa3_commit_rt(IPA_IP_v4))
965 return -EPERM;
966 if (ipa3_commit_rt(IPA_IP_v6))
967 return -EPERM;
968
969 mutex_lock(&ipa3_ctx->lock);
970 if (ipa3_ctx->ctrl->ipa3_commit_hdr()) {
971 result = -EPERM;
972 goto bail;
973 }
974 result = 0;
975bail:
976 mutex_unlock(&ipa3_ctx->lock);
977 return result;
978}
979
980/**
981 * ipa3_reset_hdr() - reset the current header table in SW (does not commit to
982 * HW)
983 *
Skylar Chang68c37d82018-04-07 16:42:36 -0700984 * @user_only: [in] indicate delete rules installed by userspace
Amir Levy9659e592016-10-27 18:08:27 +0300985 * Returns: 0 on success, negative on failure
986 *
987 * Note: Should not be called from atomic context
988 */
Skylar Chang68c37d82018-04-07 16:42:36 -0700989int ipa3_reset_hdr(bool user_only)
Amir Levy9659e592016-10-27 18:08:27 +0300990{
991 struct ipa3_hdr_entry *entry;
992 struct ipa3_hdr_entry *next;
993 struct ipa3_hdr_proc_ctx_entry *ctx_entry;
994 struct ipa3_hdr_proc_ctx_entry *ctx_next;
995 struct ipa_hdr_offset_entry *off_entry;
996 struct ipa_hdr_offset_entry *off_next;
997 struct ipa3_hdr_proc_ctx_offset_entry *ctx_off_entry;
998 struct ipa3_hdr_proc_ctx_offset_entry *ctx_off_next;
Skylar Chang1504c602018-04-21 01:42:45 -0700999 int i, end = 0;
1000 bool user_rule = false;
Amir Levy9659e592016-10-27 18:08:27 +03001001
1002 /*
1003 * issue a reset on the routing module since routing rules point to
1004 * header table entries
1005 */
Skylar Chang68c37d82018-04-07 16:42:36 -07001006 if (ipa3_reset_rt(IPA_IP_v4, user_only))
Amir Levy9659e592016-10-27 18:08:27 +03001007 IPAERR("fail to reset v4 rt\n");
Skylar Chang68c37d82018-04-07 16:42:36 -07001008 if (ipa3_reset_rt(IPA_IP_v6, user_only))
Amir Levy9659e592016-10-27 18:08:27 +03001009 IPAERR("fail to reset v4 rt\n");
1010
1011 mutex_lock(&ipa3_ctx->lock);
1012 IPADBG("reset hdr\n");
1013 list_for_each_entry_safe(entry, next,
1014 &ipa3_ctx->hdr_tbl.head_hdr_entry_list, link) {
1015
1016 /* do not remove the default header */
1017 if (!strcmp(entry->name, IPA_LAN_RX_HDR_NAME)) {
Ghanim Fodi3be117a2017-12-19 19:15:19 +02001018 IPADBG("Trying to remove hdr %s offset=%u\n",
1019 entry->name, entry->offset_entry->offset);
1020 if (!entry->offset_entry->offset) {
1021 if (entry->is_hdr_proc_ctx) {
1022 IPAERR("default header is proc ctx\n");
1023 mutex_unlock(&ipa3_ctx->lock);
1024 WARN_ON_RATELIMIT_IPA(1);
1025 return -EFAULT;
1026 }
1027 IPADBG("skip default header\n");
1028 continue;
Amir Levy9659e592016-10-27 18:08:27 +03001029 }
Amir Levy9659e592016-10-27 18:08:27 +03001030 }
1031
1032 if (ipa3_id_find(entry->id) == NULL) {
1033 mutex_unlock(&ipa3_ctx->lock);
Mohammed Javida4252d82017-10-13 13:51:21 +05301034 WARN_ON_RATELIMIT_IPA(1);
Amir Levy9659e592016-10-27 18:08:27 +03001035 return -EFAULT;
1036 }
Skylar Chang68c37d82018-04-07 16:42:36 -07001037
Skylar Chang1504c602018-04-21 01:42:45 -07001038 if (entry->ipacm_installed)
1039 user_rule = true;
1040
Skylar Chang68c37d82018-04-07 16:42:36 -07001041 if (!user_only || entry->ipacm_installed) {
1042 if (entry->is_hdr_proc_ctx) {
1043 dma_unmap_single(ipa3_ctx->pdev,
1044 entry->phys_base,
1045 entry->hdr_len,
1046 DMA_TO_DEVICE);
1047 entry->proc_ctx = NULL;
1048 }
1049 list_del(&entry->link);
Skylar Chang1504c602018-04-21 01:42:45 -07001050 ipa3_ctx->hdr_tbl.hdr_cnt--;
Skylar Chang68c37d82018-04-07 16:42:36 -07001051 entry->ref_cnt = 0;
1052 entry->cookie = 0;
1053
1054 /* remove the handle from the database */
1055 ipa3_id_remove(entry->id);
1056 kmem_cache_free(ipa3_ctx->hdr_cache, entry);
Amir Levy9659e592016-10-27 18:08:27 +03001057 }
Amir Levy9659e592016-10-27 18:08:27 +03001058 }
1059 for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
1060 list_for_each_entry_safe(off_entry, off_next,
1061 &ipa3_ctx->hdr_tbl.head_offset_list[i],
1062 link) {
1063
1064 /*
1065 * do not remove the default exception header which is
1066 * at offset 0
1067 */
1068 if (off_entry->offset == 0)
1069 continue;
1070
Skylar Chang68c37d82018-04-07 16:42:36 -07001071 if (!user_only ||
1072 off_entry->ipacm_installed) {
1073 list_del(&off_entry->link);
1074 kmem_cache_free(ipa3_ctx->hdr_offset_cache,
1075 off_entry);
Skylar Chang1504c602018-04-21 01:42:45 -07001076 } else {
1077 if (off_entry->offset +
1078 ipa_hdr_bin_sz[off_entry->bin] > end) {
1079 end = off_entry->offset +
1080 ipa_hdr_bin_sz[off_entry->bin];
1081 IPADBG("replace end = %d\n", end);
1082 }
Skylar Chang68c37d82018-04-07 16:42:36 -07001083 }
Amir Levy9659e592016-10-27 18:08:27 +03001084 }
1085 list_for_each_entry_safe(off_entry, off_next,
1086 &ipa3_ctx->hdr_tbl.head_free_offset_list[i],
1087 link) {
Skylar Chang68c37d82018-04-07 16:42:36 -07001088
1089 if (!user_only ||
1090 off_entry->ipacm_installed) {
1091 list_del(&off_entry->link);
1092 kmem_cache_free(ipa3_ctx->hdr_offset_cache,
1093 off_entry);
1094 }
Amir Levy9659e592016-10-27 18:08:27 +03001095 }
1096 }
Amir Levy9659e592016-10-27 18:08:27 +03001097
Skylar Chang1504c602018-04-21 01:42:45 -07001098 IPADBG("hdr_tbl.end = %d\n", end);
1099 if (user_rule) {
1100 ipa3_ctx->hdr_tbl.end = end;
1101 IPADBG("hdr_tbl.end = %d\n", end);
1102 }
Amir Levy9659e592016-10-27 18:08:27 +03001103 IPADBG("reset hdr proc ctx\n");
Skylar Chang1504c602018-04-21 01:42:45 -07001104 user_rule = false;
1105 end = 0;
Amir Levy9659e592016-10-27 18:08:27 +03001106 list_for_each_entry_safe(
1107 ctx_entry,
1108 ctx_next,
1109 &ipa3_ctx->hdr_proc_ctx_tbl.head_proc_ctx_entry_list,
1110 link) {
1111
1112 if (ipa3_id_find(ctx_entry->id) == NULL) {
1113 mutex_unlock(&ipa3_ctx->lock);
Mohammed Javida4252d82017-10-13 13:51:21 +05301114 WARN_ON_RATELIMIT_IPA(1);
Amir Levy9659e592016-10-27 18:08:27 +03001115 return -EFAULT;
1116 }
Amir Levy9659e592016-10-27 18:08:27 +03001117
Skylar Chang1504c602018-04-21 01:42:45 -07001118 if (entry->ipacm_installed)
1119 user_rule = true;
1120
Skylar Chang68c37d82018-04-07 16:42:36 -07001121 if (!user_only ||
1122 ctx_entry->ipacm_installed) {
1123 list_del(&ctx_entry->link);
Skylar Chang1504c602018-04-21 01:42:45 -07001124 ipa3_ctx->hdr_proc_ctx_tbl.proc_ctx_cnt--;
Skylar Chang68c37d82018-04-07 16:42:36 -07001125 ctx_entry->ref_cnt = 0;
1126 ctx_entry->cookie = 0;
Amir Levy9659e592016-10-27 18:08:27 +03001127
Skylar Chang68c37d82018-04-07 16:42:36 -07001128 /* remove the handle from the database */
1129 ipa3_id_remove(ctx_entry->id);
1130 kmem_cache_free(ipa3_ctx->hdr_proc_ctx_cache,
1131 ctx_entry);
1132 }
Amir Levy9659e592016-10-27 18:08:27 +03001133 }
1134 for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) {
1135 list_for_each_entry_safe(ctx_off_entry, ctx_off_next,
1136 &ipa3_ctx->hdr_proc_ctx_tbl.head_offset_list[i],
1137 link) {
1138
Skylar Chang68c37d82018-04-07 16:42:36 -07001139 if (!user_only ||
1140 ctx_off_entry->ipacm_installed) {
1141 list_del(&ctx_off_entry->link);
1142 kmem_cache_free(
1143 ipa3_ctx->hdr_proc_ctx_offset_cache,
Amir Levy9659e592016-10-27 18:08:27 +03001144 ctx_off_entry);
Skylar Chang1504c602018-04-21 01:42:45 -07001145 } else {
1146 if (ctx_off_entry->offset +
1147 ipa_hdr_bin_sz[ctx_off_entry->bin]
1148 > end) {
1149 end = ctx_off_entry->offset +
1150 ipa_hdr_bin_sz[ctx_off_entry->bin];
1151 IPADBG("replace hdr_proc as %d\n", end);
1152 }
Skylar Chang68c37d82018-04-07 16:42:36 -07001153 }
Amir Levy9659e592016-10-27 18:08:27 +03001154 }
1155 list_for_each_entry_safe(ctx_off_entry, ctx_off_next,
1156 &ipa3_ctx->hdr_proc_ctx_tbl.head_free_offset_list[i],
1157 link) {
Skylar Chang68c37d82018-04-07 16:42:36 -07001158
1159 if (!user_only ||
1160 ctx_off_entry->ipacm_installed) {
1161 list_del(&ctx_off_entry->link);
1162 kmem_cache_free(
1163 ipa3_ctx->hdr_proc_ctx_offset_cache,
1164 ctx_off_entry);
1165 }
Amir Levy9659e592016-10-27 18:08:27 +03001166 }
1167 }
Skylar Chang1504c602018-04-21 01:42:45 -07001168
1169 IPADBG("hdr_proc_tbl.end = %d\n", end);
1170 if (user_rule) {
1171 ipa3_ctx->hdr_proc_ctx_tbl.end = end;
1172 IPADBG("hdr_proc_tbl.end = %d\n", end);
1173 }
Amir Levy9659e592016-10-27 18:08:27 +03001174
Skylar Chang5ec274f2018-05-03 02:18:34 -07001175 /* commit the change to IPA-HW */
1176 if (ipa3_ctx->ctrl->ipa3_commit_hdr()) {
1177 IPAERR("fail to commit hdr\n");
1178 WARN_ON_RATELIMIT_IPA(1);
1179 mutex_unlock(&ipa3_ctx->lock);
1180 return -EFAULT;
1181 }
1182
1183 mutex_unlock(&ipa3_ctx->lock);
Amir Levy9659e592016-10-27 18:08:27 +03001184 return 0;
1185}
1186
1187static struct ipa3_hdr_entry *__ipa_find_hdr(const char *name)
1188{
1189 struct ipa3_hdr_entry *entry;
1190
1191 if (strnlen(name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301192 IPAERR_RL("Header name too long: %s\n", name);
Amir Levy9659e592016-10-27 18:08:27 +03001193 return NULL;
1194 }
1195
1196 list_for_each_entry(entry, &ipa3_ctx->hdr_tbl.head_hdr_entry_list,
1197 link) {
1198 if (!strcmp(name, entry->name))
1199 return entry;
1200 }
1201
1202 return NULL;
1203}
1204
1205/**
1206 * ipa3_get_hdr() - Lookup the specified header resource
1207 * @lookup: [inout] header to lookup and its handle
1208 *
1209 * lookup the specified header resource and return handle if it exists
1210 *
1211 * Returns: 0 on success, negative on failure
1212 *
1213 * Note: Should not be called from atomic context
1214 * Caller should call ipa3_put_hdr later if this function succeeds
1215 */
1216int ipa3_get_hdr(struct ipa_ioc_get_hdr *lookup)
1217{
1218 struct ipa3_hdr_entry *entry;
1219 int result = -1;
1220
1221 if (lookup == NULL) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301222 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +03001223 return -EINVAL;
1224 }
1225 mutex_lock(&ipa3_ctx->lock);
Mohammed Javidcd665892017-10-11 17:05:57 +05301226 lookup->name[IPA_RESOURCE_NAME_MAX-1] = '\0';
Amir Levy9659e592016-10-27 18:08:27 +03001227 entry = __ipa_find_hdr(lookup->name);
1228 if (entry) {
1229 lookup->hdl = entry->id;
1230 result = 0;
1231 }
1232 mutex_unlock(&ipa3_ctx->lock);
1233
1234 return result;
1235}
1236
1237/**
1238 * __ipa3_release_hdr() - drop reference to header and cause
1239 * deletion if reference count permits
1240 * @hdr_hdl: [in] handle of header to be released
1241 *
1242 * Returns: 0 on success, negative on failure
1243 */
1244int __ipa3_release_hdr(u32 hdr_hdl)
1245{
1246 int result = 0;
1247
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02001248 if (__ipa3_del_hdr(hdr_hdl, false)) {
Amir Levy9659e592016-10-27 18:08:27 +03001249 IPADBG("fail to del hdr %x\n", hdr_hdl);
1250 result = -EFAULT;
1251 goto bail;
1252 }
1253
1254 /* commit for put */
1255 if (ipa3_ctx->ctrl->ipa3_commit_hdr()) {
1256 IPAERR("fail to commit hdr\n");
1257 result = -EFAULT;
1258 goto bail;
1259 }
1260
1261bail:
1262 return result;
1263}
1264
1265/**
1266 * __ipa3_release_hdr_proc_ctx() - drop reference to processing context
1267 * and cause deletion if reference count permits
1268 * @proc_ctx_hdl: [in] handle of processing context to be released
1269 *
1270 * Returns: 0 on success, negative on failure
1271 */
1272int __ipa3_release_hdr_proc_ctx(u32 proc_ctx_hdl)
1273{
1274 int result = 0;
1275
Ghanim Fodi2c8ba072017-01-12 15:14:15 +02001276 if (__ipa3_del_hdr_proc_ctx(proc_ctx_hdl, true, false)) {
Amir Levy9659e592016-10-27 18:08:27 +03001277 IPADBG("fail to del hdr %x\n", proc_ctx_hdl);
1278 result = -EFAULT;
1279 goto bail;
1280 }
1281
1282 /* commit for put */
1283 if (ipa3_ctx->ctrl->ipa3_commit_hdr()) {
1284 IPAERR("fail to commit hdr\n");
1285 result = -EFAULT;
1286 goto bail;
1287 }
1288
1289bail:
1290 return result;
1291}
1292
1293/**
1294 * ipa3_put_hdr() - Release the specified header handle
1295 * @hdr_hdl: [in] the header handle to release
1296 *
1297 * Returns: 0 on success, negative on failure
1298 *
1299 * Note: Should not be called from atomic context
1300 */
1301int ipa3_put_hdr(u32 hdr_hdl)
1302{
1303 struct ipa3_hdr_entry *entry;
1304 int result = -EFAULT;
1305
1306 mutex_lock(&ipa3_ctx->lock);
1307
1308 entry = ipa3_id_find(hdr_hdl);
1309 if (entry == NULL) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301310 IPAERR_RL("lookup failed\n");
Amir Levy9659e592016-10-27 18:08:27 +03001311 result = -EINVAL;
1312 goto bail;
1313 }
1314
Mohammed Javid93e94ce2017-06-15 15:39:04 +05301315 if (entry->cookie != IPA_HDR_COOKIE) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301316 IPAERR_RL("invalid header entry\n");
Amir Levy9659e592016-10-27 18:08:27 +03001317 result = -EINVAL;
1318 goto bail;
1319 }
1320
1321 result = 0;
1322bail:
1323 mutex_unlock(&ipa3_ctx->lock);
1324 return result;
1325}
1326
1327/**
1328 * ipa3_copy_hdr() - Lookup the specified header resource and return a copy of
1329 * it
1330 * @copy: [inout] header to lookup and its copy
1331 *
1332 * lookup the specified header resource and return a copy of it (along with its
1333 * attributes) if it exists, this would be called for partial headers
1334 *
1335 * Returns: 0 on success, negative on failure
1336 *
1337 * Note: Should not be called from atomic context
1338 */
1339int ipa3_copy_hdr(struct ipa_ioc_copy_hdr *copy)
1340{
1341 struct ipa3_hdr_entry *entry;
1342 int result = -EFAULT;
1343
1344 if (copy == NULL) {
Utkarsh Saxenae9782812017-05-26 17:20:32 +05301345 IPAERR_RL("bad parm\n");
Amir Levy9659e592016-10-27 18:08:27 +03001346 return -EINVAL;
1347 }
1348 mutex_lock(&ipa3_ctx->lock);
Mohammed Javidcd665892017-10-11 17:05:57 +05301349 copy->name[IPA_RESOURCE_NAME_MAX-1] = '\0';
Amir Levy9659e592016-10-27 18:08:27 +03001350 entry = __ipa_find_hdr(copy->name);
1351 if (entry) {
1352 memcpy(copy->hdr, entry->hdr, entry->hdr_len);
1353 copy->hdr_len = entry->hdr_len;
1354 copy->type = entry->type;
1355 copy->is_partial = entry->is_partial;
1356 copy->is_eth2_ofst_valid = entry->is_eth2_ofst_valid;
1357 copy->eth2_ofst = entry->eth2_ofst;
1358 result = 0;
1359 }
1360 mutex_unlock(&ipa3_ctx->lock);
1361
1362 return result;
1363}