blob: d015b22f04aae87b78f49a8d8d4ab2fe6745e470 [file] [log] [blame]
Ghanim Fodi37b64952017-01-24 15:42:30 +02001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Amir Levy9659e592016-10-27 18:08:27 +03002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/debugfs.h>
14#include "ipahal.h"
15#include "ipahal_i.h"
16#include "ipahal_reg_i.h"
17#include "ipahal_fltrt_i.h"
Skylar Chang2c470a62017-07-25 10:10:44 -070018#include "ipahal_hw_stats_i.h"
Amir Levy479cfdd2017-10-26 12:23:14 +030019#include "ipahal_nat_i.h"
Amir Levy9659e592016-10-27 18:08:27 +030020
21struct ipahal_context *ipahal_ctx;
22
23static const char *ipahal_imm_cmd_name_to_str[IPA_IMM_CMD_MAX] = {
24 __stringify(IPA_IMM_CMD_IP_V4_FILTER_INIT),
25 __stringify(IPA_IMM_CMD_IP_V6_FILTER_INIT),
26 __stringify(IPA_IMM_CMD_IP_V4_NAT_INIT),
27 __stringify(IPA_IMM_CMD_IP_V4_ROUTING_INIT),
28 __stringify(IPA_IMM_CMD_IP_V6_ROUTING_INIT),
29 __stringify(IPA_IMM_CMD_HDR_INIT_LOCAL),
30 __stringify(IPA_IMM_CMD_HDR_INIT_SYSTEM),
31 __stringify(IPA_IMM_CMD_REGISTER_WRITE),
32 __stringify(IPA_IMM_CMD_NAT_DMA),
33 __stringify(IPA_IMM_CMD_IP_PACKET_INIT),
34 __stringify(IPA_IMM_CMD_DMA_SHARED_MEM),
35 __stringify(IPA_IMM_CMD_IP_PACKET_TAG_STATUS),
36 __stringify(IPA_IMM_CMD_DMA_TASK_32B_ADDR),
Amir Levy05fccd02017-06-13 16:25:45 +030037 __stringify(IPA_IMM_CMD_TABLE_DMA),
Amir Levy479cfdd2017-10-26 12:23:14 +030038 __stringify(IPA_IMM_CMD_IP_V6_CT_INIT)
Amir Levy9659e592016-10-27 18:08:27 +030039};
40
41static const char *ipahal_pkt_status_exception_to_str
42 [IPAHAL_PKT_STATUS_EXCEPTION_MAX] = {
43 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_NONE),
44 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_DEAGGR),
45 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_IPTYPE),
46 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_PACKET_LENGTH),
47 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_PACKET_THRESHOLD),
48 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_FRAG_RULE_MISS),
49 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_SW_FILT),
50 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_NAT),
Amir Levydc65f4c2017-07-06 09:49:50 +030051 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_IPV6CT),
Amir Levy9659e592016-10-27 18:08:27 +030052};
53
Michael Adisumartab5d170f2017-05-17 14:34:11 -070054static u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd);
55
Amir Levy9659e592016-10-27 18:08:27 +030056
57static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_dma_task_32b_addr(
58 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
59{
60 struct ipahal_imm_cmd_pyld *pyld;
61 struct ipa_imm_cmd_hw_dma_task_32b_addr *data;
62 struct ipahal_imm_cmd_dma_task_32b_addr *dma_params =
63 (struct ipahal_imm_cmd_dma_task_32b_addr *)params;
64
65 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
66 if (unlikely(!pyld)) {
67 IPAHAL_ERR("kzalloc err\n");
68 return pyld;
69 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -070070 /* Currently supports only one packet */
71 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd) + (1 << 8);
Amir Levy9659e592016-10-27 18:08:27 +030072 pyld->len = sizeof(*data);
73 data = (struct ipa_imm_cmd_hw_dma_task_32b_addr *)pyld->data;
74
75 if (unlikely(dma_params->size1 & ~0xFFFF)) {
76 IPAHAL_ERR("Size1 is bigger than 16bit width 0x%x\n",
77 dma_params->size1);
78 WARN_ON(1);
79 }
80 if (unlikely(dma_params->packet_size & ~0xFFFF)) {
81 IPAHAL_ERR("Pkt size is bigger than 16bit width 0x%x\n",
82 dma_params->packet_size);
83 WARN_ON(1);
84 }
85 data->cmplt = dma_params->cmplt ? 1 : 0;
86 data->eof = dma_params->eof ? 1 : 0;
87 data->flsh = dma_params->flsh ? 1 : 0;
88 data->lock = dma_params->lock ? 1 : 0;
89 data->unlock = dma_params->unlock ? 1 : 0;
90 data->size1 = dma_params->size1;
91 data->addr1 = dma_params->addr1;
92 data->packet_size = dma_params->packet_size;
93
94 return pyld;
95}
96
97static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_packet_tag_status(
98 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
99{
100 struct ipahal_imm_cmd_pyld *pyld;
101 struct ipa_imm_cmd_hw_ip_packet_tag_status *data;
102 struct ipahal_imm_cmd_ip_packet_tag_status *tag_params =
103 (struct ipahal_imm_cmd_ip_packet_tag_status *)params;
104
105 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
106 if (unlikely(!pyld)) {
107 IPAHAL_ERR("kzalloc err\n");
108 return pyld;
109 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700110 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300111 pyld->len = sizeof(*data);
112 data = (struct ipa_imm_cmd_hw_ip_packet_tag_status *)pyld->data;
113
114 if (unlikely(tag_params->tag & ~0xFFFFFFFFFFFF)) {
115 IPAHAL_ERR("tag is bigger than 48bit width 0x%llx\n",
116 tag_params->tag);
117 WARN_ON(1);
118 }
119 data->tag = tag_params->tag;
120
121 return pyld;
122}
123
124static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_dma_shared_mem(
125 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
126{
127 struct ipahal_imm_cmd_pyld *pyld;
128 struct ipa_imm_cmd_hw_dma_shared_mem *data;
129 struct ipahal_imm_cmd_dma_shared_mem *mem_params =
130 (struct ipahal_imm_cmd_dma_shared_mem *)params;
131
132 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
133 if (unlikely(!pyld)) {
134 IPAHAL_ERR("kzalloc err\n");
135 return pyld;
136 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700137 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300138 pyld->len = sizeof(*data);
139 data = (struct ipa_imm_cmd_hw_dma_shared_mem *)pyld->data;
140
141 if (unlikely(mem_params->size & ~0xFFFF)) {
142 IPAHAL_ERR("Size is bigger than 16bit width 0x%x\n",
143 mem_params->size);
144 WARN_ON(1);
145 }
146 if (unlikely(mem_params->local_addr & ~0xFFFF)) {
147 IPAHAL_ERR("Local addr is bigger than 16bit width 0x%x\n",
148 mem_params->local_addr);
149 WARN_ON(1);
150 }
151 data->direction = mem_params->is_read ? 1 : 0;
152 data->size = mem_params->size;
153 data->local_addr = mem_params->local_addr;
154 data->system_addr = mem_params->system_addr;
155 data->skip_pipeline_clear = mem_params->skip_pipeline_clear ? 1 : 0;
156 switch (mem_params->pipeline_clear_options) {
157 case IPAHAL_HPS_CLEAR:
158 data->pipeline_clear_options = 0;
159 break;
160 case IPAHAL_SRC_GRP_CLEAR:
161 data->pipeline_clear_options = 1;
162 break;
163 case IPAHAL_FULL_PIPELINE_CLEAR:
164 data->pipeline_clear_options = 2;
165 break;
166 default:
167 IPAHAL_ERR("unsupported pipline clear option %d\n",
168 mem_params->pipeline_clear_options);
169 WARN_ON(1);
170 };
171
172 return pyld;
173}
174
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700175static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_dma_shared_mem_v_4_0(
176 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
177{
178 struct ipahal_imm_cmd_pyld *pyld;
179 struct ipa_imm_cmd_hw_dma_shared_mem_v_4_0 *data;
180 struct ipahal_imm_cmd_dma_shared_mem *mem_params =
181 (struct ipahal_imm_cmd_dma_shared_mem *)params;
182
183 if (unlikely(mem_params->size & ~0xFFFF)) {
184 IPAHAL_ERR("Size is bigger than 16bit width 0x%x\n",
185 mem_params->size);
186 WARN_ON(1);
187 return NULL;
188 }
189 if (unlikely(mem_params->local_addr & ~0xFFFF)) {
190 IPAHAL_ERR("Local addr is bigger than 16bit width 0x%x\n",
191 mem_params->local_addr);
192 WARN_ON(1);
193 return NULL;
194 }
195
196 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
197 if (unlikely(!pyld)) {
198 WARN_ON(1);
199 return pyld;
200 }
201
202 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
203 pyld->len = sizeof(*data);
204 data = (struct ipa_imm_cmd_hw_dma_shared_mem_v_4_0 *)pyld->data;
205
206 data->direction = mem_params->is_read ? 1 : 0;
207 data->clear_after_read = mem_params->clear_after_read;
208 data->size = mem_params->size;
209 data->local_addr = mem_params->local_addr;
210 data->system_addr = mem_params->system_addr;
211 pyld->opcode |= (mem_params->skip_pipeline_clear ? 1 : 0) << 8;
212 switch (mem_params->pipeline_clear_options) {
213 case IPAHAL_HPS_CLEAR:
214 break;
215 case IPAHAL_SRC_GRP_CLEAR:
216 pyld->opcode |= (1 << 9);
217 break;
218 case IPAHAL_FULL_PIPELINE_CLEAR:
219 pyld->opcode |= (2 << 9);
220 break;
221 default:
222 IPAHAL_ERR("unsupported pipline clear option %d\n",
223 mem_params->pipeline_clear_options);
224 WARN_ON(1);
225 };
226
227 return pyld;
228}
229
Amir Levy9659e592016-10-27 18:08:27 +0300230static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_register_write(
231 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
232{
233 struct ipahal_imm_cmd_pyld *pyld;
234 struct ipa_imm_cmd_hw_register_write *data;
235 struct ipahal_imm_cmd_register_write *regwrt_params =
236 (struct ipahal_imm_cmd_register_write *)params;
237
238 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
239 if (unlikely(!pyld)) {
240 IPAHAL_ERR("kzalloc err\n");
241 return pyld;
242 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700243 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300244 pyld->len = sizeof(*data);
245 data = (struct ipa_imm_cmd_hw_register_write *)pyld->data;
246
247 if (unlikely(regwrt_params->offset & ~0xFFFF)) {
248 IPAHAL_ERR("Offset is bigger than 16bit width 0x%x\n",
249 regwrt_params->offset);
250 WARN_ON(1);
251 }
252 data->offset = regwrt_params->offset;
253 data->value = regwrt_params->value;
254 data->value_mask = regwrt_params->value_mask;
255
256 data->skip_pipeline_clear = regwrt_params->skip_pipeline_clear ? 1 : 0;
257 switch (regwrt_params->pipeline_clear_options) {
258 case IPAHAL_HPS_CLEAR:
259 data->pipeline_clear_options = 0;
260 break;
261 case IPAHAL_SRC_GRP_CLEAR:
262 data->pipeline_clear_options = 1;
263 break;
264 case IPAHAL_FULL_PIPELINE_CLEAR:
265 data->pipeline_clear_options = 2;
266 break;
267 default:
268 IPAHAL_ERR("unsupported pipline clear option %d\n",
269 regwrt_params->pipeline_clear_options);
270 WARN_ON(1);
271 };
272
273 return pyld;
274}
275
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700276static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_register_write_v_4_0(
277 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
278{
279 struct ipahal_imm_cmd_pyld *pyld;
280 struct ipa_imm_cmd_hw_register_write_v_4_0 *data;
281 struct ipahal_imm_cmd_register_write *regwrt_params =
282 (struct ipahal_imm_cmd_register_write *)params;
283
284 if (unlikely(regwrt_params->offset & ~0xFFFF)) {
285 IPAHAL_ERR("Offset is bigger than 16bit width 0x%x\n",
286 regwrt_params->offset);
287 WARN_ON(1);
288 return NULL;
289 }
290
291 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
292 if (unlikely(!pyld)) {
293 WARN_ON(1);
294 return pyld;
295 }
296 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
297 pyld->len = sizeof(*data);
298 data = (struct ipa_imm_cmd_hw_register_write_v_4_0 *)pyld->data;
299
300 data->offset = regwrt_params->offset;
301 data->offset_high = regwrt_params->offset >> 16;
302 data->value = regwrt_params->value;
303 data->value_mask = regwrt_params->value_mask;
304
305 pyld->opcode |= (regwrt_params->skip_pipeline_clear ? 1 : 0) << 8;
306 switch (regwrt_params->pipeline_clear_options) {
307 case IPAHAL_HPS_CLEAR:
308 break;
309 case IPAHAL_SRC_GRP_CLEAR:
310 pyld->opcode |= (1 << 9);
311 break;
312 case IPAHAL_FULL_PIPELINE_CLEAR:
313 pyld->opcode |= (2 << 9);
314 break;
315 default:
316 IPAHAL_ERR("unsupported pipline clear option %d\n",
317 regwrt_params->pipeline_clear_options);
318 WARN_ON(1);
319 };
320
321 return pyld;
322}
323
Amir Levy9659e592016-10-27 18:08:27 +0300324static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_packet_init(
325 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
326{
327 struct ipahal_imm_cmd_pyld *pyld;
328 struct ipa_imm_cmd_hw_ip_packet_init *data;
329 struct ipahal_imm_cmd_ip_packet_init *pktinit_params =
330 (struct ipahal_imm_cmd_ip_packet_init *)params;
331
332 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
333 if (unlikely(!pyld)) {
334 IPAHAL_ERR("kzalloc err\n");
335 return pyld;
336 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700337 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300338 pyld->len = sizeof(*data);
339 data = (struct ipa_imm_cmd_hw_ip_packet_init *)pyld->data;
340
341 if (unlikely(pktinit_params->destination_pipe_index & ~0x1F)) {
342 IPAHAL_ERR("Dst pipe idx is bigger than 5bit width 0x%x\n",
343 pktinit_params->destination_pipe_index);
344 WARN_ON(1);
345 }
346 data->destination_pipe_index = pktinit_params->destination_pipe_index;
347
348 return pyld;
349}
350
351static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_nat_dma(
352 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
353{
354 struct ipahal_imm_cmd_pyld *pyld;
355 struct ipa_imm_cmd_hw_nat_dma *data;
Amir Levy479cfdd2017-10-26 12:23:14 +0300356 struct ipahal_imm_cmd_table_dma *nat_params =
357 (struct ipahal_imm_cmd_table_dma *)params;
Amir Levy9659e592016-10-27 18:08:27 +0300358
359 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
360 if (unlikely(!pyld)) {
361 IPAHAL_ERR("kzalloc err\n");
362 return pyld;
363 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700364 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300365 pyld->len = sizeof(*data);
366 data = (struct ipa_imm_cmd_hw_nat_dma *)pyld->data;
367
368 data->table_index = nat_params->table_index;
369 data->base_addr = nat_params->base_addr;
370 data->offset = nat_params->offset;
371 data->data = nat_params->data;
372
373 return pyld;
374}
375
Amir Levy05fccd02017-06-13 16:25:45 +0300376static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_table_dma_ipav4(
377 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
378{
379 struct ipahal_imm_cmd_pyld *pyld;
380 struct ipa_imm_cmd_hw_table_dma_ipav4 *data;
381 struct ipahal_imm_cmd_table_dma *nat_params =
382 (struct ipahal_imm_cmd_table_dma *)params;
383
384 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
385 if (unlikely(!pyld)) {
386 IPAHAL_ERR("kzalloc err\n");
387 return pyld;
388 }
389 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
390 pyld->len = sizeof(*data);
391 data = (struct ipa_imm_cmd_hw_table_dma_ipav4 *)pyld->data;
392
393 data->table_index = nat_params->table_index;
394 data->base_addr = nat_params->base_addr;
395 data->offset = nat_params->offset;
396 data->data = nat_params->data;
397
398 return pyld;
399}
400
Amir Levy9659e592016-10-27 18:08:27 +0300401static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_hdr_init_system(
402 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
403{
404 struct ipahal_imm_cmd_pyld *pyld;
405 struct ipa_imm_cmd_hw_hdr_init_system *data;
406 struct ipahal_imm_cmd_hdr_init_system *syshdr_params =
407 (struct ipahal_imm_cmd_hdr_init_system *)params;
408
409 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
410 if (unlikely(!pyld)) {
411 IPAHAL_ERR("kzalloc err\n");
412 return pyld;
413 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700414 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300415 pyld->len = sizeof(*data);
416 data = (struct ipa_imm_cmd_hw_hdr_init_system *)pyld->data;
417
418 data->hdr_table_addr = syshdr_params->hdr_table_addr;
419
420 return pyld;
421}
422
423static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_hdr_init_local(
424 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
425{
426 struct ipahal_imm_cmd_pyld *pyld;
427 struct ipa_imm_cmd_hw_hdr_init_local *data;
428 struct ipahal_imm_cmd_hdr_init_local *lclhdr_params =
429 (struct ipahal_imm_cmd_hdr_init_local *)params;
430
431 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
432 if (unlikely(!pyld)) {
433 IPAHAL_ERR("kzalloc err\n");
434 return pyld;
435 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700436 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300437 pyld->len = sizeof(*data);
438 data = (struct ipa_imm_cmd_hw_hdr_init_local *)pyld->data;
439
440 if (unlikely(lclhdr_params->size_hdr_table & ~0xFFF)) {
441 IPAHAL_ERR("Hdr tble size is bigger than 12bit width 0x%x\n",
442 lclhdr_params->size_hdr_table);
443 WARN_ON(1);
444 }
445 data->hdr_table_addr = lclhdr_params->hdr_table_addr;
446 data->size_hdr_table = lclhdr_params->size_hdr_table;
447 data->hdr_addr = lclhdr_params->hdr_addr;
448
449 return pyld;
450}
451
452static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v6_routing_init(
453 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
454{
455 struct ipahal_imm_cmd_pyld *pyld;
456 struct ipa_imm_cmd_hw_ip_v6_routing_init *data;
457 struct ipahal_imm_cmd_ip_v6_routing_init *rt6_params =
458 (struct ipahal_imm_cmd_ip_v6_routing_init *)params;
459
460 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
461 if (unlikely(!pyld)) {
462 IPAHAL_ERR("kzalloc err\n");
463 return pyld;
464 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700465 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300466 pyld->len = sizeof(*data);
467 data = (struct ipa_imm_cmd_hw_ip_v6_routing_init *)pyld->data;
468
469 data->hash_rules_addr = rt6_params->hash_rules_addr;
470 data->hash_rules_size = rt6_params->hash_rules_size;
471 data->hash_local_addr = rt6_params->hash_local_addr;
472 data->nhash_rules_addr = rt6_params->nhash_rules_addr;
473 data->nhash_rules_size = rt6_params->nhash_rules_size;
474 data->nhash_local_addr = rt6_params->nhash_local_addr;
475
476 return pyld;
477}
478
479static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v4_routing_init(
480 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
481{
482 struct ipahal_imm_cmd_pyld *pyld;
483 struct ipa_imm_cmd_hw_ip_v4_routing_init *data;
484 struct ipahal_imm_cmd_ip_v4_routing_init *rt4_params =
485 (struct ipahal_imm_cmd_ip_v4_routing_init *)params;
486
487 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
488 if (unlikely(!pyld)) {
489 IPAHAL_ERR("kzalloc err\n");
490 return pyld;
491 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700492 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300493 pyld->len = sizeof(*data);
494 data = (struct ipa_imm_cmd_hw_ip_v4_routing_init *)pyld->data;
495
496 data->hash_rules_addr = rt4_params->hash_rules_addr;
497 data->hash_rules_size = rt4_params->hash_rules_size;
498 data->hash_local_addr = rt4_params->hash_local_addr;
499 data->nhash_rules_addr = rt4_params->nhash_rules_addr;
500 data->nhash_rules_size = rt4_params->nhash_rules_size;
501 data->nhash_local_addr = rt4_params->nhash_local_addr;
502
503 return pyld;
504}
505
506static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v4_nat_init(
507 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
508{
509 struct ipahal_imm_cmd_pyld *pyld;
510 struct ipa_imm_cmd_hw_ip_v4_nat_init *data;
511 struct ipahal_imm_cmd_ip_v4_nat_init *nat4_params =
512 (struct ipahal_imm_cmd_ip_v4_nat_init *)params;
513
514 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
515 if (unlikely(!pyld)) {
516 IPAHAL_ERR("kzalloc err\n");
517 return pyld;
518 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700519 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300520 pyld->len = sizeof(*data);
521 data = (struct ipa_imm_cmd_hw_ip_v4_nat_init *)pyld->data;
522
Amir Levy479cfdd2017-10-26 12:23:14 +0300523 data->ipv4_rules_addr = nat4_params->table_init.base_table_addr;
Amir Levy9659e592016-10-27 18:08:27 +0300524 data->ipv4_expansion_rules_addr =
Amir Levy479cfdd2017-10-26 12:23:14 +0300525 nat4_params->table_init.expansion_table_addr;
Amir Levy9659e592016-10-27 18:08:27 +0300526 data->index_table_addr = nat4_params->index_table_addr;
527 data->index_table_expansion_addr =
528 nat4_params->index_table_expansion_addr;
Amir Levy479cfdd2017-10-26 12:23:14 +0300529 data->table_index = nat4_params->table_init.table_index;
Amir Levy9659e592016-10-27 18:08:27 +0300530 data->ipv4_rules_addr_type =
Amir Levy479cfdd2017-10-26 12:23:14 +0300531 nat4_params->table_init.base_table_addr_shared ? 1 : 0;
Amir Levy9659e592016-10-27 18:08:27 +0300532 data->ipv4_expansion_rules_addr_type =
Amir Levy479cfdd2017-10-26 12:23:14 +0300533 nat4_params->table_init.expansion_table_addr_shared ? 1 : 0;
Amir Levy9659e592016-10-27 18:08:27 +0300534 data->index_table_addr_type =
535 nat4_params->index_table_addr_shared ? 1 : 0;
536 data->index_table_expansion_addr_type =
537 nat4_params->index_table_expansion_addr_shared ? 1 : 0;
Amir Levy479cfdd2017-10-26 12:23:14 +0300538 data->size_base_tables = nat4_params->table_init.size_base_table;
539 data->size_expansion_tables =
540 nat4_params->table_init.size_expansion_table;
541 data->public_addr_info = nat4_params->public_addr_info;
542
543 return pyld;
544}
545
546static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v6_ct_init(
547 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
548{
549 struct ipahal_imm_cmd_pyld *pyld;
550 struct ipa_imm_cmd_hw_ip_v6_ct_init *data;
551 struct ipahal_imm_cmd_ip_v6_ct_init *ipv6ct_params =
552 (struct ipahal_imm_cmd_ip_v6_ct_init *)params;
553
554 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
555 if (unlikely(!pyld))
556 return pyld;
557 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
558 pyld->len = sizeof(*data);
559 data = (struct ipa_imm_cmd_hw_ip_v6_ct_init *)pyld->data;
560
561 data->table_addr = ipv6ct_params->table_init.base_table_addr;
562 data->expansion_table_addr =
563 ipv6ct_params->table_init.expansion_table_addr;
564 data->table_index = ipv6ct_params->table_init.table_index;
565 data->table_addr_type =
566 ipv6ct_params->table_init.base_table_addr_shared ? 1 : 0;
567 data->expansion_table_addr_type =
568 ipv6ct_params->table_init.expansion_table_addr_shared ? 1 : 0;
569 data->size_base_table = ipv6ct_params->table_init.size_base_table;
570 data->size_expansion_table =
571 ipv6ct_params->table_init.size_expansion_table;
Amir Levy9659e592016-10-27 18:08:27 +0300572
573 return pyld;
574}
575
576static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v6_filter_init(
577 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
578{
579 struct ipahal_imm_cmd_pyld *pyld;
580 struct ipa_imm_cmd_hw_ip_v6_filter_init *data;
581 struct ipahal_imm_cmd_ip_v6_filter_init *flt6_params =
582 (struct ipahal_imm_cmd_ip_v6_filter_init *)params;
583
584 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
585 if (unlikely(!pyld)) {
586 IPAHAL_ERR("kzalloc err\n");
587 return pyld;
588 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700589 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300590 pyld->len = sizeof(*data);
591 data = (struct ipa_imm_cmd_hw_ip_v6_filter_init *)pyld->data;
592
593 data->hash_rules_addr = flt6_params->hash_rules_addr;
594 data->hash_rules_size = flt6_params->hash_rules_size;
595 data->hash_local_addr = flt6_params->hash_local_addr;
596 data->nhash_rules_addr = flt6_params->nhash_rules_addr;
597 data->nhash_rules_size = flt6_params->nhash_rules_size;
598 data->nhash_local_addr = flt6_params->nhash_local_addr;
599
600 return pyld;
601}
602
603static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v4_filter_init(
604 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
605{
606 struct ipahal_imm_cmd_pyld *pyld;
607 struct ipa_imm_cmd_hw_ip_v4_filter_init *data;
608 struct ipahal_imm_cmd_ip_v4_filter_init *flt4_params =
609 (struct ipahal_imm_cmd_ip_v4_filter_init *)params;
610
611 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
612 if (unlikely(!pyld)) {
613 IPAHAL_ERR("kzalloc err\n");
614 return pyld;
615 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700616 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300617 pyld->len = sizeof(*data);
618 data = (struct ipa_imm_cmd_hw_ip_v4_filter_init *)pyld->data;
619
620 data->hash_rules_addr = flt4_params->hash_rules_addr;
621 data->hash_rules_size = flt4_params->hash_rules_size;
622 data->hash_local_addr = flt4_params->hash_local_addr;
623 data->nhash_rules_addr = flt4_params->nhash_rules_addr;
624 data->nhash_rules_size = flt4_params->nhash_rules_size;
625 data->nhash_local_addr = flt4_params->nhash_local_addr;
626
627 return pyld;
628}
629
Amir Levy419fb8e2017-09-06 09:23:37 +0300630static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_dummy(
631 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
632{
633 IPAHAL_ERR("no construct function for IMM_CMD=%s, IPA ver %d\n",
634 ipahal_imm_cmd_name_str(cmd), ipahal_ctx->hw_type);
635 WARN_ON(1);
636 return NULL;
637}
638
Amir Levy9659e592016-10-27 18:08:27 +0300639/*
640 * struct ipahal_imm_cmd_obj - immediate command H/W information for
641 * specific IPA version
642 * @construct - CB to construct imm command payload from abstracted structure
643 * @opcode - Immediate command OpCode
Amir Levy9659e592016-10-27 18:08:27 +0300644 */
645struct ipahal_imm_cmd_obj {
646 struct ipahal_imm_cmd_pyld *(*construct)(enum ipahal_imm_cmd_name cmd,
647 const void *params, bool is_atomic_ctx);
648 u16 opcode;
Amir Levy9659e592016-10-27 18:08:27 +0300649};
650
651/*
652 * This table contains the info regard each immediate command for IPAv3
653 * and later.
654 * Information like: opcode and construct functions.
655 * All the information on the IMM on IPAv3 are statically defined below.
656 * If information is missing regard some IMM on some IPA version,
657 * the init function will fill it with the information from the previous
658 * IPA version.
659 * Information is considered missing if all of the fields are 0
660 * If opcode is -1, this means that the IMM is removed on the
661 * specific version
662 */
663static struct ipahal_imm_cmd_obj
664 ipahal_imm_cmd_objs[IPA_HW_MAX][IPA_IMM_CMD_MAX] = {
665 /* IPAv3 */
666 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V4_FILTER_INIT] = {
667 ipa_imm_cmd_construct_ip_v4_filter_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700668 3},
Amir Levy9659e592016-10-27 18:08:27 +0300669 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V6_FILTER_INIT] = {
670 ipa_imm_cmd_construct_ip_v6_filter_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700671 4},
Amir Levy9659e592016-10-27 18:08:27 +0300672 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V4_NAT_INIT] = {
673 ipa_imm_cmd_construct_ip_v4_nat_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700674 5},
Amir Levy9659e592016-10-27 18:08:27 +0300675 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V4_ROUTING_INIT] = {
676 ipa_imm_cmd_construct_ip_v4_routing_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700677 7},
Amir Levy9659e592016-10-27 18:08:27 +0300678 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V6_ROUTING_INIT] = {
679 ipa_imm_cmd_construct_ip_v6_routing_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700680 8},
Amir Levy9659e592016-10-27 18:08:27 +0300681 [IPA_HW_v3_0][IPA_IMM_CMD_HDR_INIT_LOCAL] = {
682 ipa_imm_cmd_construct_hdr_init_local,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700683 9},
Amir Levy9659e592016-10-27 18:08:27 +0300684 [IPA_HW_v3_0][IPA_IMM_CMD_HDR_INIT_SYSTEM] = {
685 ipa_imm_cmd_construct_hdr_init_system,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700686 10},
Amir Levy9659e592016-10-27 18:08:27 +0300687 [IPA_HW_v3_0][IPA_IMM_CMD_REGISTER_WRITE] = {
688 ipa_imm_cmd_construct_register_write,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700689 12},
Amir Levy9659e592016-10-27 18:08:27 +0300690 [IPA_HW_v3_0][IPA_IMM_CMD_NAT_DMA] = {
691 ipa_imm_cmd_construct_nat_dma,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700692 14},
Amir Levy9659e592016-10-27 18:08:27 +0300693 [IPA_HW_v3_0][IPA_IMM_CMD_IP_PACKET_INIT] = {
694 ipa_imm_cmd_construct_ip_packet_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700695 16},
Amir Levy9659e592016-10-27 18:08:27 +0300696 [IPA_HW_v3_0][IPA_IMM_CMD_DMA_TASK_32B_ADDR] = {
697 ipa_imm_cmd_construct_dma_task_32b_addr,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700698 17},
Amir Levy9659e592016-10-27 18:08:27 +0300699 [IPA_HW_v3_0][IPA_IMM_CMD_DMA_SHARED_MEM] = {
700 ipa_imm_cmd_construct_dma_shared_mem,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700701 19},
Amir Levy9659e592016-10-27 18:08:27 +0300702 [IPA_HW_v3_0][IPA_IMM_CMD_IP_PACKET_TAG_STATUS] = {
703 ipa_imm_cmd_construct_ip_packet_tag_status,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700704 20},
705
706 /* IPAv4 */
707 [IPA_HW_v4_0][IPA_IMM_CMD_REGISTER_WRITE] = {
708 ipa_imm_cmd_construct_register_write_v_4_0,
709 12},
Amir Levy05fccd02017-06-13 16:25:45 +0300710 /* NAT_DMA was renamed to TABLE_DMA for IPAv4 */
711 [IPA_HW_v4_0][IPA_IMM_CMD_NAT_DMA] = {
Amir Levy419fb8e2017-09-06 09:23:37 +0300712 ipa_imm_cmd_construct_dummy,
713 -1},
Amir Levy05fccd02017-06-13 16:25:45 +0300714 [IPA_HW_v4_0][IPA_IMM_CMD_TABLE_DMA] = {
715 ipa_imm_cmd_construct_table_dma_ipav4,
716 14},
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700717 [IPA_HW_v4_0][IPA_IMM_CMD_DMA_SHARED_MEM] = {
718 ipa_imm_cmd_construct_dma_shared_mem_v_4_0,
719 19},
Amir Levy479cfdd2017-10-26 12:23:14 +0300720 [IPA_HW_v4_0][IPA_IMM_CMD_IP_V6_CT_INIT] = {
721 ipa_imm_cmd_construct_ip_v6_ct_init,
722 23}
Amir Levy9659e592016-10-27 18:08:27 +0300723};
724
725/*
726 * ipahal_imm_cmd_init() - Build the Immediate command information table
727 * See ipahal_imm_cmd_objs[][] comments
728 */
729static int ipahal_imm_cmd_init(enum ipa_hw_type ipa_hw_type)
730{
731 int i;
732 int j;
733 struct ipahal_imm_cmd_obj zero_obj;
734
735 IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type);
736
737 if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) {
738 IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
739 return -EINVAL;
740 }
741
742 memset(&zero_obj, 0, sizeof(zero_obj));
743 for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; i++) {
744 for (j = 0; j < IPA_IMM_CMD_MAX ; j++) {
745 if (!memcmp(&ipahal_imm_cmd_objs[i+1][j], &zero_obj,
746 sizeof(struct ipahal_imm_cmd_obj))) {
747 memcpy(&ipahal_imm_cmd_objs[i+1][j],
748 &ipahal_imm_cmd_objs[i][j],
749 sizeof(struct ipahal_imm_cmd_obj));
750 } else {
751 /*
752 * explicitly overridden immediate command.
753 * Check validity
754 */
755 if (!ipahal_imm_cmd_objs[i+1][j].opcode) {
756 IPAHAL_ERR(
757 "imm_cmd=%s with zero opcode ipa_ver=%d\n",
758 ipahal_imm_cmd_name_str(j), i+1);
759 WARN_ON(1);
760 }
761 if (!ipahal_imm_cmd_objs[i+1][j].construct) {
762 IPAHAL_ERR(
763 "imm_cmd=%s with NULL construct func ipa_ver=%d\n",
764 ipahal_imm_cmd_name_str(j), i+1);
765 WARN_ON(1);
766 }
767 }
768 }
769 }
770
771 return 0;
772}
773
774/*
775 * ipahal_imm_cmd_name_str() - returns string that represent the imm cmd
776 * @cmd_name: [in] Immediate command name
777 */
778const char *ipahal_imm_cmd_name_str(enum ipahal_imm_cmd_name cmd_name)
779{
780 if (cmd_name < 0 || cmd_name >= IPA_IMM_CMD_MAX) {
781 IPAHAL_ERR("requested name of invalid imm_cmd=%d\n", cmd_name);
782 return "Invalid IMM_CMD";
783 }
784
785 return ipahal_imm_cmd_name_to_str[cmd_name];
786}
787
788/*
789 * ipahal_imm_cmd_get_opcode() - Get the fixed opcode of the immediate command
790 */
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700791static u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd)
Amir Levy9659e592016-10-27 18:08:27 +0300792{
793 u32 opcode;
794
795 if (cmd >= IPA_IMM_CMD_MAX) {
796 IPAHAL_ERR("Invalid immediate command imm_cmd=%u\n", cmd);
797 ipa_assert();
798 return -EFAULT;
799 }
800
801 IPAHAL_DBG_LOW("Get opcode of IMM_CMD=%s\n",
802 ipahal_imm_cmd_name_str(cmd));
803 opcode = ipahal_imm_cmd_objs[ipahal_ctx->hw_type][cmd].opcode;
804 if (opcode == -1) {
805 IPAHAL_ERR("Try to get opcode of obsolete IMM_CMD=%s\n",
806 ipahal_imm_cmd_name_str(cmd));
807 ipa_assert();
808 return -EFAULT;
809 }
810
811 return opcode;
812}
813
814/*
Amir Levy9659e592016-10-27 18:08:27 +0300815 * ipahal_construct_imm_cmd() - Construct immdiate command
816 * This function builds imm cmd bulk that can be be sent to IPA
817 * The command will be allocated dynamically.
818 * After done using it, call ipahal_destroy_imm_cmd() to release it
819 */
820struct ipahal_imm_cmd_pyld *ipahal_construct_imm_cmd(
821 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
822{
823 if (!params) {
824 IPAHAL_ERR("Input error: params=%p\n", params);
825 ipa_assert();
826 return NULL;
827 }
828
829 if (cmd >= IPA_IMM_CMD_MAX) {
830 IPAHAL_ERR("Invalid immediate command %u\n", cmd);
831 ipa_assert();
832 return NULL;
833 }
834
835 IPAHAL_DBG_LOW("construct IMM_CMD:%s\n", ipahal_imm_cmd_name_str(cmd));
836 return ipahal_imm_cmd_objs[ipahal_ctx->hw_type][cmd].construct(
837 cmd, params, is_atomic_ctx);
838}
839
840/*
841 * ipahal_construct_nop_imm_cmd() - Construct immediate comamnd for NO-Op
842 * Core driver may want functionality to inject NOP commands to IPA
843 * to ensure e.g., PIPLINE clear before someother operation.
844 * The functionality given by this function can be reached by
845 * ipahal_construct_imm_cmd(). This function is helper to the core driver
846 * to reach this NOP functionlity easily.
847 * @skip_pipline_clear: if to skip pipeline clear waiting (don't wait)
848 * @pipline_clr_opt: options for pipeline clear waiting
849 * @is_atomic_ctx: is called in atomic context or can sleep?
850 */
851struct ipahal_imm_cmd_pyld *ipahal_construct_nop_imm_cmd(
852 bool skip_pipline_clear,
853 enum ipahal_pipeline_clear_option pipline_clr_opt,
854 bool is_atomic_ctx)
855{
856 struct ipahal_imm_cmd_register_write cmd;
857 struct ipahal_imm_cmd_pyld *cmd_pyld;
858
859 memset(&cmd, 0, sizeof(cmd));
860 cmd.skip_pipeline_clear = skip_pipline_clear;
861 cmd.pipeline_clear_options = pipline_clr_opt;
862 cmd.value_mask = 0x0;
863
864 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
865 &cmd, is_atomic_ctx);
866
867 if (!cmd_pyld)
868 IPAHAL_ERR("failed to construct register_write imm cmd\n");
869
870 return cmd_pyld;
871}
872
873
874/* IPA Packet Status Logic */
875
876#define IPA_PKT_STATUS_SET_MSK(__hw_bit_msk, __shft) \
877 (status->status_mask |= \
878 ((hw_status->status_mask & (__hw_bit_msk) ? 1 : 0) << (__shft)))
879
880static void ipa_pkt_status_parse(
881 const void *unparsed_status, struct ipahal_pkt_status *status)
882{
883 enum ipahal_pkt_status_opcode opcode = 0;
884 enum ipahal_pkt_status_exception exception_type = 0;
Amir Levydc65f4c2017-07-06 09:49:50 +0300885 bool is_ipv6;
Amir Levy9659e592016-10-27 18:08:27 +0300886
887 struct ipa_pkt_status_hw *hw_status =
888 (struct ipa_pkt_status_hw *)unparsed_status;
889
Amir Levydc65f4c2017-07-06 09:49:50 +0300890 is_ipv6 = (hw_status->status_mask & 0x80) ? false : true;
891
Amir Levy9659e592016-10-27 18:08:27 +0300892 status->pkt_len = hw_status->pkt_len;
893 status->endp_src_idx = hw_status->endp_src_idx;
894 status->endp_dest_idx = hw_status->endp_dest_idx;
895 status->metadata = hw_status->metadata;
896 status->flt_local = hw_status->flt_local;
897 status->flt_hash = hw_status->flt_hash;
898 status->flt_global = hw_status->flt_hash;
899 status->flt_ret_hdr = hw_status->flt_ret_hdr;
900 status->flt_miss = ~(hw_status->flt_rule_id) ? false : true;
901 status->flt_rule_id = hw_status->flt_rule_id;
902 status->rt_local = hw_status->rt_local;
903 status->rt_hash = hw_status->rt_hash;
904 status->ucp = hw_status->ucp;
905 status->rt_tbl_idx = hw_status->rt_tbl_idx;
906 status->rt_miss = ~(hw_status->rt_rule_id) ? false : true;
907 status->rt_rule_id = hw_status->rt_rule_id;
908 status->nat_hit = hw_status->nat_hit;
909 status->nat_entry_idx = hw_status->nat_entry_idx;
910 status->tag_info = hw_status->tag_info;
911 status->seq_num = hw_status->seq_num;
912 status->time_of_day_ctr = hw_status->time_of_day_ctr;
913 status->hdr_local = hw_status->hdr_local;
914 status->hdr_offset = hw_status->hdr_offset;
915 status->frag_hit = hw_status->frag_hit;
916 status->frag_rule = hw_status->frag_rule;
917
918 switch (hw_status->status_opcode) {
919 case 0x1:
920 opcode = IPAHAL_PKT_STATUS_OPCODE_PACKET;
921 break;
922 case 0x2:
923 opcode = IPAHAL_PKT_STATUS_OPCODE_NEW_FRAG_RULE;
924 break;
925 case 0x4:
926 opcode = IPAHAL_PKT_STATUS_OPCODE_DROPPED_PACKET;
927 break;
928 case 0x8:
929 opcode = IPAHAL_PKT_STATUS_OPCODE_SUSPENDED_PACKET;
930 break;
931 case 0x10:
932 opcode = IPAHAL_PKT_STATUS_OPCODE_LOG;
933 break;
934 case 0x20:
935 opcode = IPAHAL_PKT_STATUS_OPCODE_DCMP;
936 break;
937 case 0x40:
938 opcode = IPAHAL_PKT_STATUS_OPCODE_PACKET_2ND_PASS;
939 break;
940 default:
941 IPAHAL_ERR("unsupported Status Opcode 0x%x\n",
942 hw_status->status_opcode);
943 WARN_ON(1);
944 };
945 status->status_opcode = opcode;
946
947 switch (hw_status->nat_type) {
948 case 0:
949 status->nat_type = IPAHAL_PKT_STATUS_NAT_NONE;
950 break;
951 case 1:
952 status->nat_type = IPAHAL_PKT_STATUS_NAT_SRC;
953 break;
954 case 2:
955 status->nat_type = IPAHAL_PKT_STATUS_NAT_DST;
956 break;
957 default:
958 IPAHAL_ERR("unsupported Status NAT type 0x%x\n",
959 hw_status->nat_type);
960 WARN_ON(1);
961 };
962
963 switch (hw_status->exception) {
964 case 0:
965 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_NONE;
966 break;
967 case 1:
968 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_DEAGGR;
969 break;
970 case 4:
971 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_IPTYPE;
972 break;
973 case 8:
974 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_PACKET_LENGTH;
975 break;
976 case 16:
977 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_FRAG_RULE_MISS;
978 break;
979 case 32:
980 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_SW_FILT;
981 break;
982 case 64:
Amir Levydc65f4c2017-07-06 09:49:50 +0300983 if (is_ipv6)
984 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_IPV6CT;
985 else
986 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_NAT;
Amir Levy9659e592016-10-27 18:08:27 +0300987 break;
988 default:
989 IPAHAL_ERR("unsupported Status Exception type 0x%x\n",
990 hw_status->exception);
991 WARN_ON(1);
992 };
993 status->exception = exception_type;
994
995 IPA_PKT_STATUS_SET_MSK(0x1, IPAHAL_PKT_STATUS_MASK_FRAG_PROCESS_SHFT);
996 IPA_PKT_STATUS_SET_MSK(0x2, IPAHAL_PKT_STATUS_MASK_FILT_PROCESS_SHFT);
997 IPA_PKT_STATUS_SET_MSK(0x4, IPAHAL_PKT_STATUS_MASK_NAT_PROCESS_SHFT);
998 IPA_PKT_STATUS_SET_MSK(0x8, IPAHAL_PKT_STATUS_MASK_ROUTE_PROCESS_SHFT);
999 IPA_PKT_STATUS_SET_MSK(0x10, IPAHAL_PKT_STATUS_MASK_TAG_VALID_SHFT);
1000 IPA_PKT_STATUS_SET_MSK(0x20, IPAHAL_PKT_STATUS_MASK_FRAGMENT_SHFT);
1001 IPA_PKT_STATUS_SET_MSK(0x40,
1002 IPAHAL_PKT_STATUS_MASK_FIRST_FRAGMENT_SHFT);
1003 IPA_PKT_STATUS_SET_MSK(0x80, IPAHAL_PKT_STATUS_MASK_V4_SHFT);
1004 IPA_PKT_STATUS_SET_MSK(0x100,
1005 IPAHAL_PKT_STATUS_MASK_CKSUM_PROCESS_SHFT);
1006 IPA_PKT_STATUS_SET_MSK(0x200, IPAHAL_PKT_STATUS_MASK_AGGR_PROCESS_SHFT);
1007 IPA_PKT_STATUS_SET_MSK(0x400, IPAHAL_PKT_STATUS_MASK_DEST_EOT_SHFT);
1008 IPA_PKT_STATUS_SET_MSK(0x800,
1009 IPAHAL_PKT_STATUS_MASK_DEAGGR_PROCESS_SHFT);
1010 IPA_PKT_STATUS_SET_MSK(0x1000, IPAHAL_PKT_STATUS_MASK_DEAGG_FIRST_SHFT);
1011 IPA_PKT_STATUS_SET_MSK(0x2000, IPAHAL_PKT_STATUS_MASK_SRC_EOT_SHFT);
1012 IPA_PKT_STATUS_SET_MSK(0x4000, IPAHAL_PKT_STATUS_MASK_PREV_EOT_SHFT);
1013 IPA_PKT_STATUS_SET_MSK(0x8000, IPAHAL_PKT_STATUS_MASK_BYTE_LIMIT_SHFT);
1014 status->status_mask &= 0xFFFF;
1015}
1016
1017/*
1018 * struct ipahal_pkt_status_obj - Pakcet Status H/W information for
1019 * specific IPA version
1020 * @size: H/W size of the status packet
1021 * @parse: CB that parses the H/W packet status into the abstracted structure
1022 */
1023struct ipahal_pkt_status_obj {
1024 u32 size;
1025 void (*parse)(const void *unparsed_status,
1026 struct ipahal_pkt_status *status);
1027};
1028
1029/*
1030 * This table contains the info regard packet status for IPAv3 and later
1031 * Information like: size of packet status and parsing function
1032 * All the information on the pkt Status on IPAv3 are statically defined below.
1033 * If information is missing regard some IPA version, the init function
1034 * will fill it with the information from the previous IPA version.
1035 * Information is considered missing if all of the fields are 0
1036 */
1037static struct ipahal_pkt_status_obj ipahal_pkt_status_objs[IPA_HW_MAX] = {
1038 /* IPAv3 */
1039 [IPA_HW_v3_0] = {
1040 IPA3_0_PKT_STATUS_SIZE,
1041 ipa_pkt_status_parse,
1042 },
1043};
1044
1045/*
1046 * ipahal_pkt_status_init() - Build the packet status information array
1047 * for the different IPA versions
1048 * See ipahal_pkt_status_objs[] comments
1049 */
1050static int ipahal_pkt_status_init(enum ipa_hw_type ipa_hw_type)
1051{
1052 int i;
1053 struct ipahal_pkt_status_obj zero_obj;
1054
1055 IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type);
1056
1057 if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) {
1058 IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
1059 return -EINVAL;
1060 }
1061
1062 /*
1063 * Since structure alignment is implementation dependent,
1064 * add test to avoid different and incompatible data layouts.
1065 *
1066 * In case new H/W has different size or structure of status packet,
1067 * add a compile time validty check for it like below (as well as
1068 * the new defines and/or the new strucutre in the internal header).
1069 */
1070 BUILD_BUG_ON(sizeof(struct ipa_pkt_status_hw) !=
1071 IPA3_0_PKT_STATUS_SIZE);
1072
1073 memset(&zero_obj, 0, sizeof(zero_obj));
1074 for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; i++) {
1075 if (!memcmp(&ipahal_pkt_status_objs[i+1], &zero_obj,
1076 sizeof(struct ipahal_pkt_status_obj))) {
1077 memcpy(&ipahal_pkt_status_objs[i+1],
1078 &ipahal_pkt_status_objs[i],
1079 sizeof(struct ipahal_pkt_status_obj));
1080 } else {
1081 /*
1082 * explicitly overridden Packet Status info
1083 * Check validity
1084 */
1085 if (!ipahal_pkt_status_objs[i+1].size) {
1086 IPAHAL_ERR(
1087 "Packet Status with zero size ipa_ver=%d\n",
1088 i+1);
1089 WARN_ON(1);
1090 }
1091 if (!ipahal_pkt_status_objs[i+1].parse) {
1092 IPAHAL_ERR(
1093 "Packet Status without Parse func ipa_ver=%d\n",
1094 i+1);
1095 WARN_ON(1);
1096 }
1097 }
1098 }
1099
1100 return 0;
1101}
1102
1103/*
1104 * ipahal_pkt_status_get_size() - Get H/W size of packet status
1105 */
1106u32 ipahal_pkt_status_get_size(void)
1107{
1108 return ipahal_pkt_status_objs[ipahal_ctx->hw_type].size;
1109}
1110
1111/*
1112 * ipahal_pkt_status_parse() - Parse Packet Status payload to abstracted form
1113 * @unparsed_status: Pointer to H/W format of the packet status as read from H/W
1114 * @status: Pointer to pre-allocated buffer where the parsed info will be stored
1115 */
1116void ipahal_pkt_status_parse(const void *unparsed_status,
1117 struct ipahal_pkt_status *status)
1118{
1119 if (!unparsed_status || !status) {
1120 IPAHAL_ERR("Input Error: unparsed_status=%p status=%p\n",
1121 unparsed_status, status);
1122 return;
1123 }
1124
1125 IPAHAL_DBG_LOW("Parse Status Packet\n");
1126 memset(status, 0, sizeof(*status));
1127 ipahal_pkt_status_objs[ipahal_ctx->hw_type].parse(unparsed_status,
1128 status);
1129}
1130
1131/*
1132 * ipahal_pkt_status_exception_str() - returns string represents exception type
1133 * @exception: [in] The exception type
1134 */
1135const char *ipahal_pkt_status_exception_str(
1136 enum ipahal_pkt_status_exception exception)
1137{
1138 if (exception < 0 || exception >= IPAHAL_PKT_STATUS_EXCEPTION_MAX) {
1139 IPAHAL_ERR(
1140 "requested string of invalid pkt_status exception=%d\n",
1141 exception);
1142 return "Invalid PKT_STATUS_EXCEPTION";
1143 }
1144
1145 return ipahal_pkt_status_exception_to_str[exception];
1146}
1147
1148#ifdef CONFIG_DEBUG_FS
1149static void ipahal_debugfs_init(void)
1150{
1151 ipahal_ctx->dent = debugfs_create_dir("ipahal", 0);
1152 if (!ipahal_ctx->dent || IS_ERR(ipahal_ctx->dent)) {
1153 IPAHAL_ERR("fail to create ipahal debugfs folder\n");
1154 goto fail;
1155 }
1156
1157 return;
1158fail:
1159 debugfs_remove_recursive(ipahal_ctx->dent);
1160 ipahal_ctx->dent = NULL;
1161}
1162
1163static void ipahal_debugfs_remove(void)
1164{
1165 if (!ipahal_ctx)
1166 return;
1167
1168 if (IS_ERR(ipahal_ctx->dent)) {
1169 IPAHAL_ERR("ipahal debugfs folder was not created\n");
1170 return;
1171 }
1172
1173 debugfs_remove_recursive(ipahal_ctx->dent);
1174}
1175#else /* CONFIG_DEBUG_FS */
1176static void ipahal_debugfs_init(void) {}
1177static void ipahal_debugfs_remove(void) {}
1178#endif /* CONFIG_DEBUG_FS */
1179
1180/*
1181 * ipahal_cp_hdr_to_hw_buff_v3() - copy header to hardware buffer according to
1182 * base address and offset given.
1183 * @base: dma base address
1184 * @offset: offset from base address where the data will be copied
1185 * @hdr: the header to be copied
1186 * @hdr_len: the length of the header
1187 */
1188static void ipahal_cp_hdr_to_hw_buff_v3(void *const base, u32 offset,
1189 u8 *const hdr, u32 hdr_len)
1190{
1191 memcpy(base + offset, hdr, hdr_len);
1192}
1193
1194/*
1195 * ipahal_cp_proc_ctx_to_hw_buff_v3() - copy processing context to
1196 * base address and offset given.
1197 * @type: header processing context type (no processing context,
1198 * IPA_HDR_PROC_ETHII_TO_ETHII etc.)
1199 * @base: dma base address
1200 * @offset: offset from base address where the data will be copied
1201 * @hdr_len: the length of the header
1202 * @is_hdr_proc_ctx: header is located in phys_base (true) or hdr_base_addr
1203 * @phys_base: memory location in DDR
1204 * @hdr_base_addr: base address in table
1205 * @offset_entry: offset from hdr_base_addr in table
Skylar Chang7fa22712017-04-03 18:29:21 -07001206 * @l2tp_params: l2tp parameters
Amir Levy9659e592016-10-27 18:08:27 +03001207 */
1208static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type,
1209 void *const base, u32 offset,
1210 u32 hdr_len, bool is_hdr_proc_ctx,
1211 dma_addr_t phys_base, u32 hdr_base_addr,
Skylar Chang7fa22712017-04-03 18:29:21 -07001212 struct ipa_hdr_offset_entry *offset_entry,
Shihuan Liufe2818b2017-07-03 22:14:55 -07001213 struct ipa_l2tp_hdr_proc_ctx_params l2tp_params){
Amir Levy9659e592016-10-27 18:08:27 +03001214 if (type == IPA_HDR_PROC_NONE) {
1215 struct ipa_hw_hdr_proc_ctx_add_hdr_seq *ctx;
1216
1217 ctx = (struct ipa_hw_hdr_proc_ctx_add_hdr_seq *)
1218 (base + offset);
1219 ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD;
1220 ctx->hdr_add.tlv.length = 1;
1221 ctx->hdr_add.tlv.value = hdr_len;
1222 ctx->hdr_add.hdr_addr = is_hdr_proc_ctx ? phys_base :
1223 hdr_base_addr + offset_entry->offset;
1224 IPAHAL_DBG("header address 0x%x\n",
1225 ctx->hdr_add.hdr_addr);
1226 ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
1227 ctx->end.length = 0;
1228 ctx->end.value = 0;
Skylar Chang7fa22712017-04-03 18:29:21 -07001229 } else if (type == IPA_HDR_PROC_L2TP_HEADER_ADD) {
1230 struct ipa_hw_hdr_proc_ctx_add_l2tp_hdr_cmd_seq *ctx;
1231
1232 ctx = (struct ipa_hw_hdr_proc_ctx_add_l2tp_hdr_cmd_seq *)
1233 (base + offset);
1234 ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD;
1235 ctx->hdr_add.tlv.length = 1;
1236 ctx->hdr_add.tlv.value = hdr_len;
1237 ctx->hdr_add.hdr_addr = is_hdr_proc_ctx ? phys_base :
1238 hdr_base_addr + offset_entry->offset;
1239 IPAHAL_DBG("header address 0x%x\n",
1240 ctx->hdr_add.hdr_addr);
1241 ctx->l2tp_params.tlv.type = IPA_PROC_CTX_TLV_TYPE_PROC_CMD;
1242 ctx->l2tp_params.tlv.length = 1;
1243 ctx->l2tp_params.tlv.value =
1244 IPA_HDR_UCP_L2TP_HEADER_ADD;
1245 ctx->l2tp_params.l2tp_params.eth_hdr_retained =
1246 l2tp_params.hdr_add_param.eth_hdr_retained;
1247 ctx->l2tp_params.l2tp_params.input_ip_version =
1248 l2tp_params.hdr_add_param.input_ip_version;
1249 ctx->l2tp_params.l2tp_params.output_ip_version =
1250 l2tp_params.hdr_add_param.output_ip_version;
1251
1252 IPAHAL_DBG("command id %d\n", ctx->l2tp_params.tlv.value);
1253 ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
1254 ctx->end.length = 0;
1255 ctx->end.value = 0;
1256 } else if (type == IPA_HDR_PROC_L2TP_HEADER_REMOVE) {
1257 struct ipa_hw_hdr_proc_ctx_remove_l2tp_hdr_cmd_seq *ctx;
1258
1259 ctx = (struct ipa_hw_hdr_proc_ctx_remove_l2tp_hdr_cmd_seq *)
1260 (base + offset);
1261 ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD;
1262 ctx->hdr_add.tlv.length = 1;
1263 ctx->hdr_add.tlv.value = hdr_len;
1264 ctx->hdr_add.hdr_addr = is_hdr_proc_ctx ? phys_base :
1265 hdr_base_addr + offset_entry->offset;
1266 IPAHAL_DBG("header address 0x%x length %d\n",
1267 ctx->hdr_add.hdr_addr, ctx->hdr_add.tlv.value);
1268 ctx->l2tp_params.tlv.type = IPA_PROC_CTX_TLV_TYPE_PROC_CMD;
1269 ctx->l2tp_params.tlv.length = 1;
1270 ctx->l2tp_params.tlv.value =
1271 IPA_HDR_UCP_L2TP_HEADER_REMOVE;
1272 ctx->l2tp_params.l2tp_params.hdr_len_remove =
1273 l2tp_params.hdr_remove_param.hdr_len_remove;
1274 ctx->l2tp_params.l2tp_params.eth_hdr_retained =
1275 l2tp_params.hdr_remove_param.eth_hdr_retained;
Shihuan Liufe2818b2017-07-03 22:14:55 -07001276 ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size_valid =
1277 l2tp_params.hdr_remove_param.hdr_ofst_pkt_size_valid;
1278 ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size =
1279 l2tp_params.hdr_remove_param.hdr_ofst_pkt_size;
1280 ctx->l2tp_params.l2tp_params.hdr_endianness =
1281 l2tp_params.hdr_remove_param.hdr_endianness;
1282 IPAHAL_DBG("hdr ofst valid: %d, hdr ofst pkt size: %d\n",
1283 ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size_valid,
1284 ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size);
1285 IPAHAL_DBG("endianness: %d\n",
1286 ctx->l2tp_params.l2tp_params.hdr_endianness);
Skylar Chang7fa22712017-04-03 18:29:21 -07001287
1288 IPAHAL_DBG("command id %d\n", ctx->l2tp_params.tlv.value);
1289 ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
1290 ctx->end.length = 0;
1291 ctx->end.value = 0;
Amir Levy9659e592016-10-27 18:08:27 +03001292 } else {
1293 struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq *ctx;
1294
1295 ctx = (struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq *)
1296 (base + offset);
1297 ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD;
1298 ctx->hdr_add.tlv.length = 1;
1299 ctx->hdr_add.tlv.value = hdr_len;
1300 ctx->hdr_add.hdr_addr = is_hdr_proc_ctx ? phys_base :
1301 hdr_base_addr + offset_entry->offset;
1302 IPAHAL_DBG("header address 0x%x\n",
1303 ctx->hdr_add.hdr_addr);
1304 ctx->cmd.type = IPA_PROC_CTX_TLV_TYPE_PROC_CMD;
1305 ctx->cmd.length = 0;
1306 switch (type) {
1307 case IPA_HDR_PROC_ETHII_TO_ETHII:
1308 ctx->cmd.value = IPA_HDR_UCP_ETHII_TO_ETHII;
1309 break;
1310 case IPA_HDR_PROC_ETHII_TO_802_3:
1311 ctx->cmd.value = IPA_HDR_UCP_ETHII_TO_802_3;
1312 break;
1313 case IPA_HDR_PROC_802_3_TO_ETHII:
1314 ctx->cmd.value = IPA_HDR_UCP_802_3_TO_ETHII;
1315 break;
1316 case IPA_HDR_PROC_802_3_TO_802_3:
1317 ctx->cmd.value = IPA_HDR_UCP_802_3_TO_802_3;
1318 break;
1319 default:
1320 IPAHAL_ERR("unknown ipa_hdr_proc_type %d", type);
1321 WARN_ON(1);
1322 return -EINVAL;
1323 }
1324 IPAHAL_DBG("command id %d\n", ctx->cmd.value);
1325 ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
1326 ctx->end.length = 0;
1327 ctx->end.value = 0;
1328 }
1329
1330 return 0;
1331}
1332
1333/*
1334 * ipahal_get_proc_ctx_needed_len_v3() - calculates the needed length for
1335 * addition of header processing context according to the type of processing
1336 * context.
1337 * @type: header processing context type (no processing context,
1338 * IPA_HDR_PROC_ETHII_TO_ETHII etc.)
1339 */
1340static int ipahal_get_proc_ctx_needed_len_v3(enum ipa_hdr_proc_type type)
1341{
1342 return (type == IPA_HDR_PROC_NONE) ?
1343 sizeof(struct ipa_hw_hdr_proc_ctx_add_hdr_seq) :
1344 sizeof(struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq);
1345}
1346
1347/*
1348 * struct ipahal_hdr_funcs - headers handling functions for specific IPA
1349 * version
1350 * @ipahal_cp_hdr_to_hw_buff - copy function for regular headers
1351 */
1352struct ipahal_hdr_funcs {
1353 void (*ipahal_cp_hdr_to_hw_buff)(void *const base, u32 offset,
1354 u8 *const hdr, u32 hdr_len);
1355
1356 int (*ipahal_cp_proc_ctx_to_hw_buff)(enum ipa_hdr_proc_type type,
1357 void *const base, u32 offset, u32 hdr_len,
1358 bool is_hdr_proc_ctx, dma_addr_t phys_base,
1359 u32 hdr_base_addr,
Skylar Chang7fa22712017-04-03 18:29:21 -07001360 struct ipa_hdr_offset_entry *offset_entry,
Shihuan Liufe2818b2017-07-03 22:14:55 -07001361 struct ipa_l2tp_hdr_proc_ctx_params l2tp_params);
Amir Levy9659e592016-10-27 18:08:27 +03001362
1363 int (*ipahal_get_proc_ctx_needed_len)(enum ipa_hdr_proc_type type);
1364};
1365
1366static struct ipahal_hdr_funcs hdr_funcs;
1367
1368static void ipahal_hdr_init(enum ipa_hw_type ipa_hw_type)
1369{
1370
1371 IPAHAL_DBG("Entry - HW_TYPE=%d\n", ipa_hw_type);
1372
1373 /*
1374 * once there are changes in HW and need to use different case, insert
1375 * new case for the new h/w. put the default always for the latest HW
1376 * and make sure all previous supported versions have their cases.
1377 */
1378 switch (ipa_hw_type) {
1379 case IPA_HW_v3_0:
1380 default:
1381 hdr_funcs.ipahal_cp_hdr_to_hw_buff =
1382 ipahal_cp_hdr_to_hw_buff_v3;
1383 hdr_funcs.ipahal_cp_proc_ctx_to_hw_buff =
1384 ipahal_cp_proc_ctx_to_hw_buff_v3;
1385 hdr_funcs.ipahal_get_proc_ctx_needed_len =
1386 ipahal_get_proc_ctx_needed_len_v3;
1387 }
1388 IPAHAL_DBG("Exit\n");
1389}
1390
1391/*
1392 * ipahal_cp_hdr_to_hw_buff() - copy header to hardware buffer according to
1393 * base address and offset given.
1394 * @base: dma base address
1395 * @offset: offset from base address where the data will be copied
1396 * @hdr: the header to be copied
1397 * @hdr_len: the length of the header
1398 */
1399void ipahal_cp_hdr_to_hw_buff(void *base, u32 offset, u8 *const hdr,
1400 u32 hdr_len)
1401{
1402 IPAHAL_DBG_LOW("Entry\n");
1403 IPAHAL_DBG("base %p, offset %d, hdr %p, hdr_len %d\n", base,
1404 offset, hdr, hdr_len);
1405 if (!base || !hdr_len || !hdr) {
1406 IPAHAL_ERR("failed on validating params");
1407 return;
1408 }
1409
1410 hdr_funcs.ipahal_cp_hdr_to_hw_buff(base, offset, hdr, hdr_len);
1411
1412 IPAHAL_DBG_LOW("Exit\n");
1413}
1414
1415/*
1416 * ipahal_cp_proc_ctx_to_hw_buff() - copy processing context to
1417 * base address and offset given.
1418 * @type: type of header processing context
1419 * @base: dma base address
1420 * @offset: offset from base address where the data will be copied
1421 * @hdr_len: the length of the header
1422 * @is_hdr_proc_ctx: header is located in phys_base (true) or hdr_base_addr
1423 * @phys_base: memory location in DDR
1424 * @hdr_base_addr: base address in table
1425 * @offset_entry: offset from hdr_base_addr in table
Skylar Chang7fa22712017-04-03 18:29:21 -07001426 * @l2tp_params: l2tp parameters
Amir Levy9659e592016-10-27 18:08:27 +03001427 */
1428int ipahal_cp_proc_ctx_to_hw_buff(enum ipa_hdr_proc_type type,
1429 void *const base, u32 offset, u32 hdr_len,
1430 bool is_hdr_proc_ctx, dma_addr_t phys_base,
Skylar Chang7fa22712017-04-03 18:29:21 -07001431 u32 hdr_base_addr, struct ipa_hdr_offset_entry *offset_entry,
Shihuan Liufe2818b2017-07-03 22:14:55 -07001432 struct ipa_l2tp_hdr_proc_ctx_params l2tp_params)
Amir Levy9659e592016-10-27 18:08:27 +03001433{
1434 IPAHAL_DBG(
1435 "type %d, base %p, offset %d, hdr_len %d, is_hdr_proc_ctx %d, hdr_base_addr %d, offset_entry %p\n"
1436 , type, base, offset, hdr_len, is_hdr_proc_ctx,
1437 hdr_base_addr, offset_entry);
1438
1439 if (!base ||
1440 !hdr_len ||
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001441 (is_hdr_proc_ctx && !phys_base) ||
1442 (!is_hdr_proc_ctx && !offset_entry) ||
1443 (!is_hdr_proc_ctx && !hdr_base_addr)) {
Amir Levy9659e592016-10-27 18:08:27 +03001444 IPAHAL_ERR(
1445 "invalid input: hdr_len:%u phys_base:%pad hdr_base_addr:%u is_hdr_proc_ctx:%d offset_entry:%pK\n"
1446 , hdr_len, &phys_base, hdr_base_addr
1447 , is_hdr_proc_ctx, offset_entry);
1448 return -EINVAL;
1449 }
1450
1451 return hdr_funcs.ipahal_cp_proc_ctx_to_hw_buff(type, base, offset,
1452 hdr_len, is_hdr_proc_ctx, phys_base,
Skylar Chang7fa22712017-04-03 18:29:21 -07001453 hdr_base_addr, offset_entry, l2tp_params);
Amir Levy9659e592016-10-27 18:08:27 +03001454}
1455
1456/*
1457 * ipahal_get_proc_ctx_needed_len() - calculates the needed length for
1458 * addition of header processing context according to the type of processing
1459 * context
1460 * @type: header processing context type (no processing context,
1461 * IPA_HDR_PROC_ETHII_TO_ETHII etc.)
1462 */
1463int ipahal_get_proc_ctx_needed_len(enum ipa_hdr_proc_type type)
1464{
1465 int res;
1466
1467 IPAHAL_DBG("entry\n");
1468
1469 res = hdr_funcs.ipahal_get_proc_ctx_needed_len(type);
1470
1471 IPAHAL_DBG("Exit\n");
1472
1473 return res;
1474}
1475
Ghanim Fodi37b64952017-01-24 15:42:30 +02001476/*
1477 * Get IPA Data Processing Star image memory size at IPA SRAM
1478 */
1479u32 ipahal_get_dps_img_mem_size(void)
1480{
1481 return IPA_HW_DPS_IMG_MEM_SIZE_V3_0;
1482}
1483
1484/*
1485 * Get IPA Header Processing Star image memory size at IPA SRAM
1486 */
1487u32 ipahal_get_hps_img_mem_size(void)
1488{
1489 return IPA_HW_HPS_IMG_MEM_SIZE_V3_0;
1490}
Amir Levy9659e592016-10-27 18:08:27 +03001491
1492int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base,
1493 struct device *ipa_pdev)
1494{
1495 int result;
1496
1497 IPAHAL_DBG("Entry - IPA HW TYPE=%d base=%p ipa_pdev=%p\n",
1498 ipa_hw_type, base, ipa_pdev);
1499
1500 ipahal_ctx = kzalloc(sizeof(*ipahal_ctx), GFP_KERNEL);
1501 if (!ipahal_ctx) {
1502 IPAHAL_ERR("kzalloc err for ipahal_ctx\n");
1503 result = -ENOMEM;
1504 goto bail_err_exit;
1505 }
1506
1507 if (ipa_hw_type < IPA_HW_v3_0) {
1508 IPAHAL_ERR("ipahal supported on IPAv3 and later only\n");
1509 result = -EINVAL;
1510 goto bail_free_ctx;
1511 }
1512
1513 if (ipa_hw_type >= IPA_HW_MAX) {
1514 IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
1515 result = -EINVAL;
1516 goto bail_free_ctx;
1517 }
1518
1519 if (!base) {
1520 IPAHAL_ERR("invalid memory io mapping addr\n");
1521 result = -EINVAL;
1522 goto bail_free_ctx;
1523 }
1524
1525 if (!ipa_pdev) {
1526 IPAHAL_ERR("invalid IPA platform device\n");
1527 result = -EINVAL;
1528 goto bail_free_ctx;
1529 }
1530
1531 ipahal_ctx->hw_type = ipa_hw_type;
1532 ipahal_ctx->base = base;
1533 ipahal_ctx->ipa_pdev = ipa_pdev;
1534
1535 if (ipahal_reg_init(ipa_hw_type)) {
1536 IPAHAL_ERR("failed to init ipahal reg\n");
1537 result = -EFAULT;
1538 goto bail_free_ctx;
1539 }
1540
1541 if (ipahal_imm_cmd_init(ipa_hw_type)) {
1542 IPAHAL_ERR("failed to init ipahal imm cmd\n");
1543 result = -EFAULT;
1544 goto bail_free_ctx;
1545 }
1546
1547 if (ipahal_pkt_status_init(ipa_hw_type)) {
1548 IPAHAL_ERR("failed to init ipahal pkt status\n");
1549 result = -EFAULT;
1550 goto bail_free_ctx;
1551 }
1552
1553 ipahal_hdr_init(ipa_hw_type);
1554
1555 if (ipahal_fltrt_init(ipa_hw_type)) {
1556 IPAHAL_ERR("failed to init ipahal flt rt\n");
1557 result = -EFAULT;
1558 goto bail_free_ctx;
1559 }
1560
Skylar Chang2c470a62017-07-25 10:10:44 -07001561 if (ipahal_hw_stats_init(ipa_hw_type)) {
1562 IPAHAL_ERR("failed to init ipahal hw stats\n");
1563 result = -EFAULT;
Amir Levy479cfdd2017-10-26 12:23:14 +03001564 goto bail_free_fltrt;
1565 }
1566
1567 if (ipahal_nat_init(ipa_hw_type)) {
1568 IPAHAL_ERR("failed to init ipahal NAT\n");
1569 result = -EFAULT;
1570 goto bail_free_fltrt;
Skylar Chang2c470a62017-07-25 10:10:44 -07001571 }
1572
Amir Levy9659e592016-10-27 18:08:27 +03001573 ipahal_debugfs_init();
1574
1575 return 0;
1576
Amir Levy479cfdd2017-10-26 12:23:14 +03001577bail_free_fltrt:
1578 ipahal_fltrt_destroy();
Amir Levy9659e592016-10-27 18:08:27 +03001579bail_free_ctx:
1580 kfree(ipahal_ctx);
1581 ipahal_ctx = NULL;
1582bail_err_exit:
1583 return result;
1584}
1585
1586void ipahal_destroy(void)
1587{
1588 IPAHAL_DBG("Entry\n");
1589 ipahal_fltrt_destroy();
1590 ipahal_debugfs_remove();
1591 kfree(ipahal_ctx);
1592 ipahal_ctx = NULL;
1593}
1594
1595void ipahal_free_dma_mem(struct ipa_mem_buffer *mem)
1596{
1597 if (likely(mem)) {
1598 dma_free_coherent(ipahal_ctx->ipa_pdev, mem->size, mem->base,
1599 mem->phys_base);
1600 mem->size = 0;
1601 mem->base = NULL;
1602 mem->phys_base = 0;
1603 }
1604}