blob: d35b8a73219496bf1f4d9de4bf9844cddc8641a3 [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"
18
19struct ipahal_context *ipahal_ctx;
20
21static const char *ipahal_imm_cmd_name_to_str[IPA_IMM_CMD_MAX] = {
22 __stringify(IPA_IMM_CMD_IP_V4_FILTER_INIT),
23 __stringify(IPA_IMM_CMD_IP_V6_FILTER_INIT),
24 __stringify(IPA_IMM_CMD_IP_V4_NAT_INIT),
25 __stringify(IPA_IMM_CMD_IP_V4_ROUTING_INIT),
26 __stringify(IPA_IMM_CMD_IP_V6_ROUTING_INIT),
27 __stringify(IPA_IMM_CMD_HDR_INIT_LOCAL),
28 __stringify(IPA_IMM_CMD_HDR_INIT_SYSTEM),
29 __stringify(IPA_IMM_CMD_REGISTER_WRITE),
30 __stringify(IPA_IMM_CMD_NAT_DMA),
31 __stringify(IPA_IMM_CMD_IP_PACKET_INIT),
32 __stringify(IPA_IMM_CMD_DMA_SHARED_MEM),
33 __stringify(IPA_IMM_CMD_IP_PACKET_TAG_STATUS),
34 __stringify(IPA_IMM_CMD_DMA_TASK_32B_ADDR),
35};
36
37static const char *ipahal_pkt_status_exception_to_str
38 [IPAHAL_PKT_STATUS_EXCEPTION_MAX] = {
39 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_NONE),
40 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_DEAGGR),
41 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_IPTYPE),
42 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_PACKET_LENGTH),
43 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_PACKET_THRESHOLD),
44 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_FRAG_RULE_MISS),
45 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_SW_FILT),
46 __stringify(IPAHAL_PKT_STATUS_EXCEPTION_NAT),
47};
48
49#define IPAHAL_MEM_ALLOC(__size, __is_atomic_ctx) \
50 (kzalloc((__size), ((__is_atomic_ctx)?GFP_ATOMIC:GFP_KERNEL)))
51
Michael Adisumartab5d170f2017-05-17 14:34:11 -070052static u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd);
53
Amir Levy9659e592016-10-27 18:08:27 +030054
55static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_dma_task_32b_addr(
56 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
57{
58 struct ipahal_imm_cmd_pyld *pyld;
59 struct ipa_imm_cmd_hw_dma_task_32b_addr *data;
60 struct ipahal_imm_cmd_dma_task_32b_addr *dma_params =
61 (struct ipahal_imm_cmd_dma_task_32b_addr *)params;
62
63 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
64 if (unlikely(!pyld)) {
65 IPAHAL_ERR("kzalloc err\n");
66 return pyld;
67 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -070068 /* Currently supports only one packet */
69 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd) + (1 << 8);
Amir Levy9659e592016-10-27 18:08:27 +030070 pyld->len = sizeof(*data);
71 data = (struct ipa_imm_cmd_hw_dma_task_32b_addr *)pyld->data;
72
73 if (unlikely(dma_params->size1 & ~0xFFFF)) {
74 IPAHAL_ERR("Size1 is bigger than 16bit width 0x%x\n",
75 dma_params->size1);
76 WARN_ON(1);
77 }
78 if (unlikely(dma_params->packet_size & ~0xFFFF)) {
79 IPAHAL_ERR("Pkt size is bigger than 16bit width 0x%x\n",
80 dma_params->packet_size);
81 WARN_ON(1);
82 }
83 data->cmplt = dma_params->cmplt ? 1 : 0;
84 data->eof = dma_params->eof ? 1 : 0;
85 data->flsh = dma_params->flsh ? 1 : 0;
86 data->lock = dma_params->lock ? 1 : 0;
87 data->unlock = dma_params->unlock ? 1 : 0;
88 data->size1 = dma_params->size1;
89 data->addr1 = dma_params->addr1;
90 data->packet_size = dma_params->packet_size;
91
92 return pyld;
93}
94
95static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_packet_tag_status(
96 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
97{
98 struct ipahal_imm_cmd_pyld *pyld;
99 struct ipa_imm_cmd_hw_ip_packet_tag_status *data;
100 struct ipahal_imm_cmd_ip_packet_tag_status *tag_params =
101 (struct ipahal_imm_cmd_ip_packet_tag_status *)params;
102
103 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
104 if (unlikely(!pyld)) {
105 IPAHAL_ERR("kzalloc err\n");
106 return pyld;
107 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700108 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300109 pyld->len = sizeof(*data);
110 data = (struct ipa_imm_cmd_hw_ip_packet_tag_status *)pyld->data;
111
112 if (unlikely(tag_params->tag & ~0xFFFFFFFFFFFF)) {
113 IPAHAL_ERR("tag is bigger than 48bit width 0x%llx\n",
114 tag_params->tag);
115 WARN_ON(1);
116 }
117 data->tag = tag_params->tag;
118
119 return pyld;
120}
121
122static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_dma_shared_mem(
123 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
124{
125 struct ipahal_imm_cmd_pyld *pyld;
126 struct ipa_imm_cmd_hw_dma_shared_mem *data;
127 struct ipahal_imm_cmd_dma_shared_mem *mem_params =
128 (struct ipahal_imm_cmd_dma_shared_mem *)params;
129
130 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
131 if (unlikely(!pyld)) {
132 IPAHAL_ERR("kzalloc err\n");
133 return pyld;
134 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700135 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300136 pyld->len = sizeof(*data);
137 data = (struct ipa_imm_cmd_hw_dma_shared_mem *)pyld->data;
138
139 if (unlikely(mem_params->size & ~0xFFFF)) {
140 IPAHAL_ERR("Size is bigger than 16bit width 0x%x\n",
141 mem_params->size);
142 WARN_ON(1);
143 }
144 if (unlikely(mem_params->local_addr & ~0xFFFF)) {
145 IPAHAL_ERR("Local addr is bigger than 16bit width 0x%x\n",
146 mem_params->local_addr);
147 WARN_ON(1);
148 }
149 data->direction = mem_params->is_read ? 1 : 0;
150 data->size = mem_params->size;
151 data->local_addr = mem_params->local_addr;
152 data->system_addr = mem_params->system_addr;
153 data->skip_pipeline_clear = mem_params->skip_pipeline_clear ? 1 : 0;
154 switch (mem_params->pipeline_clear_options) {
155 case IPAHAL_HPS_CLEAR:
156 data->pipeline_clear_options = 0;
157 break;
158 case IPAHAL_SRC_GRP_CLEAR:
159 data->pipeline_clear_options = 1;
160 break;
161 case IPAHAL_FULL_PIPELINE_CLEAR:
162 data->pipeline_clear_options = 2;
163 break;
164 default:
165 IPAHAL_ERR("unsupported pipline clear option %d\n",
166 mem_params->pipeline_clear_options);
167 WARN_ON(1);
168 };
169
170 return pyld;
171}
172
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700173static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_dma_shared_mem_v_4_0(
174 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
175{
176 struct ipahal_imm_cmd_pyld *pyld;
177 struct ipa_imm_cmd_hw_dma_shared_mem_v_4_0 *data;
178 struct ipahal_imm_cmd_dma_shared_mem *mem_params =
179 (struct ipahal_imm_cmd_dma_shared_mem *)params;
180
181 if (unlikely(mem_params->size & ~0xFFFF)) {
182 IPAHAL_ERR("Size is bigger than 16bit width 0x%x\n",
183 mem_params->size);
184 WARN_ON(1);
185 return NULL;
186 }
187 if (unlikely(mem_params->local_addr & ~0xFFFF)) {
188 IPAHAL_ERR("Local addr is bigger than 16bit width 0x%x\n",
189 mem_params->local_addr);
190 WARN_ON(1);
191 return NULL;
192 }
193
194 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
195 if (unlikely(!pyld)) {
196 WARN_ON(1);
197 return pyld;
198 }
199
200 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
201 pyld->len = sizeof(*data);
202 data = (struct ipa_imm_cmd_hw_dma_shared_mem_v_4_0 *)pyld->data;
203
204 data->direction = mem_params->is_read ? 1 : 0;
205 data->clear_after_read = mem_params->clear_after_read;
206 data->size = mem_params->size;
207 data->local_addr = mem_params->local_addr;
208 data->system_addr = mem_params->system_addr;
209 pyld->opcode |= (mem_params->skip_pipeline_clear ? 1 : 0) << 8;
210 switch (mem_params->pipeline_clear_options) {
211 case IPAHAL_HPS_CLEAR:
212 break;
213 case IPAHAL_SRC_GRP_CLEAR:
214 pyld->opcode |= (1 << 9);
215 break;
216 case IPAHAL_FULL_PIPELINE_CLEAR:
217 pyld->opcode |= (2 << 9);
218 break;
219 default:
220 IPAHAL_ERR("unsupported pipline clear option %d\n",
221 mem_params->pipeline_clear_options);
222 WARN_ON(1);
223 };
224
225 return pyld;
226}
227
Amir Levy9659e592016-10-27 18:08:27 +0300228static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_register_write(
229 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
230{
231 struct ipahal_imm_cmd_pyld *pyld;
232 struct ipa_imm_cmd_hw_register_write *data;
233 struct ipahal_imm_cmd_register_write *regwrt_params =
234 (struct ipahal_imm_cmd_register_write *)params;
235
236 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
237 if (unlikely(!pyld)) {
238 IPAHAL_ERR("kzalloc err\n");
239 return pyld;
240 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700241 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300242 pyld->len = sizeof(*data);
243 data = (struct ipa_imm_cmd_hw_register_write *)pyld->data;
244
245 if (unlikely(regwrt_params->offset & ~0xFFFF)) {
246 IPAHAL_ERR("Offset is bigger than 16bit width 0x%x\n",
247 regwrt_params->offset);
248 WARN_ON(1);
249 }
250 data->offset = regwrt_params->offset;
251 data->value = regwrt_params->value;
252 data->value_mask = regwrt_params->value_mask;
253
254 data->skip_pipeline_clear = regwrt_params->skip_pipeline_clear ? 1 : 0;
255 switch (regwrt_params->pipeline_clear_options) {
256 case IPAHAL_HPS_CLEAR:
257 data->pipeline_clear_options = 0;
258 break;
259 case IPAHAL_SRC_GRP_CLEAR:
260 data->pipeline_clear_options = 1;
261 break;
262 case IPAHAL_FULL_PIPELINE_CLEAR:
263 data->pipeline_clear_options = 2;
264 break;
265 default:
266 IPAHAL_ERR("unsupported pipline clear option %d\n",
267 regwrt_params->pipeline_clear_options);
268 WARN_ON(1);
269 };
270
271 return pyld;
272}
273
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700274static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_register_write_v_4_0(
275 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
276{
277 struct ipahal_imm_cmd_pyld *pyld;
278 struct ipa_imm_cmd_hw_register_write_v_4_0 *data;
279 struct ipahal_imm_cmd_register_write *regwrt_params =
280 (struct ipahal_imm_cmd_register_write *)params;
281
282 if (unlikely(regwrt_params->offset & ~0xFFFF)) {
283 IPAHAL_ERR("Offset is bigger than 16bit width 0x%x\n",
284 regwrt_params->offset);
285 WARN_ON(1);
286 return NULL;
287 }
288
289 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
290 if (unlikely(!pyld)) {
291 WARN_ON(1);
292 return pyld;
293 }
294 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
295 pyld->len = sizeof(*data);
296 data = (struct ipa_imm_cmd_hw_register_write_v_4_0 *)pyld->data;
297
298 data->offset = regwrt_params->offset;
299 data->offset_high = regwrt_params->offset >> 16;
300 data->value = regwrt_params->value;
301 data->value_mask = regwrt_params->value_mask;
302
303 pyld->opcode |= (regwrt_params->skip_pipeline_clear ? 1 : 0) << 8;
304 switch (regwrt_params->pipeline_clear_options) {
305 case IPAHAL_HPS_CLEAR:
306 break;
307 case IPAHAL_SRC_GRP_CLEAR:
308 pyld->opcode |= (1 << 9);
309 break;
310 case IPAHAL_FULL_PIPELINE_CLEAR:
311 pyld->opcode |= (2 << 9);
312 break;
313 default:
314 IPAHAL_ERR("unsupported pipline clear option %d\n",
315 regwrt_params->pipeline_clear_options);
316 WARN_ON(1);
317 };
318
319 return pyld;
320}
321
Amir Levy9659e592016-10-27 18:08:27 +0300322static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_packet_init(
323 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
324{
325 struct ipahal_imm_cmd_pyld *pyld;
326 struct ipa_imm_cmd_hw_ip_packet_init *data;
327 struct ipahal_imm_cmd_ip_packet_init *pktinit_params =
328 (struct ipahal_imm_cmd_ip_packet_init *)params;
329
330 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
331 if (unlikely(!pyld)) {
332 IPAHAL_ERR("kzalloc err\n");
333 return pyld;
334 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700335 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300336 pyld->len = sizeof(*data);
337 data = (struct ipa_imm_cmd_hw_ip_packet_init *)pyld->data;
338
339 if (unlikely(pktinit_params->destination_pipe_index & ~0x1F)) {
340 IPAHAL_ERR("Dst pipe idx is bigger than 5bit width 0x%x\n",
341 pktinit_params->destination_pipe_index);
342 WARN_ON(1);
343 }
344 data->destination_pipe_index = pktinit_params->destination_pipe_index;
345
346 return pyld;
347}
348
349static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_nat_dma(
350 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
351{
352 struct ipahal_imm_cmd_pyld *pyld;
353 struct ipa_imm_cmd_hw_nat_dma *data;
354 struct ipahal_imm_cmd_nat_dma *nat_params =
355 (struct ipahal_imm_cmd_nat_dma *)params;
356
357 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
358 if (unlikely(!pyld)) {
359 IPAHAL_ERR("kzalloc err\n");
360 return pyld;
361 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700362 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300363 pyld->len = sizeof(*data);
364 data = (struct ipa_imm_cmd_hw_nat_dma *)pyld->data;
365
366 data->table_index = nat_params->table_index;
367 data->base_addr = nat_params->base_addr;
368 data->offset = nat_params->offset;
369 data->data = nat_params->data;
370
371 return pyld;
372}
373
374static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_hdr_init_system(
375 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
376{
377 struct ipahal_imm_cmd_pyld *pyld;
378 struct ipa_imm_cmd_hw_hdr_init_system *data;
379 struct ipahal_imm_cmd_hdr_init_system *syshdr_params =
380 (struct ipahal_imm_cmd_hdr_init_system *)params;
381
382 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
383 if (unlikely(!pyld)) {
384 IPAHAL_ERR("kzalloc err\n");
385 return pyld;
386 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700387 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300388 pyld->len = sizeof(*data);
389 data = (struct ipa_imm_cmd_hw_hdr_init_system *)pyld->data;
390
391 data->hdr_table_addr = syshdr_params->hdr_table_addr;
392
393 return pyld;
394}
395
396static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_hdr_init_local(
397 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
398{
399 struct ipahal_imm_cmd_pyld *pyld;
400 struct ipa_imm_cmd_hw_hdr_init_local *data;
401 struct ipahal_imm_cmd_hdr_init_local *lclhdr_params =
402 (struct ipahal_imm_cmd_hdr_init_local *)params;
403
404 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
405 if (unlikely(!pyld)) {
406 IPAHAL_ERR("kzalloc err\n");
407 return pyld;
408 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700409 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300410 pyld->len = sizeof(*data);
411 data = (struct ipa_imm_cmd_hw_hdr_init_local *)pyld->data;
412
413 if (unlikely(lclhdr_params->size_hdr_table & ~0xFFF)) {
414 IPAHAL_ERR("Hdr tble size is bigger than 12bit width 0x%x\n",
415 lclhdr_params->size_hdr_table);
416 WARN_ON(1);
417 }
418 data->hdr_table_addr = lclhdr_params->hdr_table_addr;
419 data->size_hdr_table = lclhdr_params->size_hdr_table;
420 data->hdr_addr = lclhdr_params->hdr_addr;
421
422 return pyld;
423}
424
425static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v6_routing_init(
426 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
427{
428 struct ipahal_imm_cmd_pyld *pyld;
429 struct ipa_imm_cmd_hw_ip_v6_routing_init *data;
430 struct ipahal_imm_cmd_ip_v6_routing_init *rt6_params =
431 (struct ipahal_imm_cmd_ip_v6_routing_init *)params;
432
433 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
434 if (unlikely(!pyld)) {
435 IPAHAL_ERR("kzalloc err\n");
436 return pyld;
437 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700438 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300439 pyld->len = sizeof(*data);
440 data = (struct ipa_imm_cmd_hw_ip_v6_routing_init *)pyld->data;
441
442 data->hash_rules_addr = rt6_params->hash_rules_addr;
443 data->hash_rules_size = rt6_params->hash_rules_size;
444 data->hash_local_addr = rt6_params->hash_local_addr;
445 data->nhash_rules_addr = rt6_params->nhash_rules_addr;
446 data->nhash_rules_size = rt6_params->nhash_rules_size;
447 data->nhash_local_addr = rt6_params->nhash_local_addr;
448
449 return pyld;
450}
451
452static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v4_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_v4_routing_init *data;
457 struct ipahal_imm_cmd_ip_v4_routing_init *rt4_params =
458 (struct ipahal_imm_cmd_ip_v4_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_v4_routing_init *)pyld->data;
468
469 data->hash_rules_addr = rt4_params->hash_rules_addr;
470 data->hash_rules_size = rt4_params->hash_rules_size;
471 data->hash_local_addr = rt4_params->hash_local_addr;
472 data->nhash_rules_addr = rt4_params->nhash_rules_addr;
473 data->nhash_rules_size = rt4_params->nhash_rules_size;
474 data->nhash_local_addr = rt4_params->nhash_local_addr;
475
476 return pyld;
477}
478
479static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v4_nat_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_nat_init *data;
484 struct ipahal_imm_cmd_ip_v4_nat_init *nat4_params =
485 (struct ipahal_imm_cmd_ip_v4_nat_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_nat_init *)pyld->data;
495
496 data->ipv4_rules_addr = nat4_params->ipv4_rules_addr;
497 data->ipv4_expansion_rules_addr =
498 nat4_params->ipv4_expansion_rules_addr;
499 data->index_table_addr = nat4_params->index_table_addr;
500 data->index_table_expansion_addr =
501 nat4_params->index_table_expansion_addr;
502 data->table_index = nat4_params->table_index;
503 data->ipv4_rules_addr_type =
504 nat4_params->ipv4_rules_addr_shared ? 1 : 0;
505 data->ipv4_expansion_rules_addr_type =
506 nat4_params->ipv4_expansion_rules_addr_shared ? 1 : 0;
507 data->index_table_addr_type =
508 nat4_params->index_table_addr_shared ? 1 : 0;
509 data->index_table_expansion_addr_type =
510 nat4_params->index_table_expansion_addr_shared ? 1 : 0;
511 data->size_base_tables = nat4_params->size_base_tables;
512 data->size_expansion_tables = nat4_params->size_expansion_tables;
513 data->public_ip_addr = nat4_params->public_ip_addr;
514
515 return pyld;
516}
517
518static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v6_filter_init(
519 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
520{
521 struct ipahal_imm_cmd_pyld *pyld;
522 struct ipa_imm_cmd_hw_ip_v6_filter_init *data;
523 struct ipahal_imm_cmd_ip_v6_filter_init *flt6_params =
524 (struct ipahal_imm_cmd_ip_v6_filter_init *)params;
525
526 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
527 if (unlikely(!pyld)) {
528 IPAHAL_ERR("kzalloc err\n");
529 return pyld;
530 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700531 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300532 pyld->len = sizeof(*data);
533 data = (struct ipa_imm_cmd_hw_ip_v6_filter_init *)pyld->data;
534
535 data->hash_rules_addr = flt6_params->hash_rules_addr;
536 data->hash_rules_size = flt6_params->hash_rules_size;
537 data->hash_local_addr = flt6_params->hash_local_addr;
538 data->nhash_rules_addr = flt6_params->nhash_rules_addr;
539 data->nhash_rules_size = flt6_params->nhash_rules_size;
540 data->nhash_local_addr = flt6_params->nhash_local_addr;
541
542 return pyld;
543}
544
545static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v4_filter_init(
546 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
547{
548 struct ipahal_imm_cmd_pyld *pyld;
549 struct ipa_imm_cmd_hw_ip_v4_filter_init *data;
550 struct ipahal_imm_cmd_ip_v4_filter_init *flt4_params =
551 (struct ipahal_imm_cmd_ip_v4_filter_init *)params;
552
553 pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
554 if (unlikely(!pyld)) {
555 IPAHAL_ERR("kzalloc err\n");
556 return pyld;
557 }
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700558 pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
Amir Levy9659e592016-10-27 18:08:27 +0300559 pyld->len = sizeof(*data);
560 data = (struct ipa_imm_cmd_hw_ip_v4_filter_init *)pyld->data;
561
562 data->hash_rules_addr = flt4_params->hash_rules_addr;
563 data->hash_rules_size = flt4_params->hash_rules_size;
564 data->hash_local_addr = flt4_params->hash_local_addr;
565 data->nhash_rules_addr = flt4_params->nhash_rules_addr;
566 data->nhash_rules_size = flt4_params->nhash_rules_size;
567 data->nhash_local_addr = flt4_params->nhash_local_addr;
568
569 return pyld;
570}
571
572/*
573 * struct ipahal_imm_cmd_obj - immediate command H/W information for
574 * specific IPA version
575 * @construct - CB to construct imm command payload from abstracted structure
576 * @opcode - Immediate command OpCode
Amir Levy9659e592016-10-27 18:08:27 +0300577 */
578struct ipahal_imm_cmd_obj {
579 struct ipahal_imm_cmd_pyld *(*construct)(enum ipahal_imm_cmd_name cmd,
580 const void *params, bool is_atomic_ctx);
581 u16 opcode;
Amir Levy9659e592016-10-27 18:08:27 +0300582};
583
584/*
585 * This table contains the info regard each immediate command for IPAv3
586 * and later.
587 * Information like: opcode and construct functions.
588 * All the information on the IMM on IPAv3 are statically defined below.
589 * If information is missing regard some IMM on some IPA version,
590 * the init function will fill it with the information from the previous
591 * IPA version.
592 * Information is considered missing if all of the fields are 0
593 * If opcode is -1, this means that the IMM is removed on the
594 * specific version
595 */
596static struct ipahal_imm_cmd_obj
597 ipahal_imm_cmd_objs[IPA_HW_MAX][IPA_IMM_CMD_MAX] = {
598 /* IPAv3 */
599 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V4_FILTER_INIT] = {
600 ipa_imm_cmd_construct_ip_v4_filter_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700601 3},
Amir Levy9659e592016-10-27 18:08:27 +0300602 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V6_FILTER_INIT] = {
603 ipa_imm_cmd_construct_ip_v6_filter_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700604 4},
Amir Levy9659e592016-10-27 18:08:27 +0300605 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V4_NAT_INIT] = {
606 ipa_imm_cmd_construct_ip_v4_nat_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700607 5},
Amir Levy9659e592016-10-27 18:08:27 +0300608 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V4_ROUTING_INIT] = {
609 ipa_imm_cmd_construct_ip_v4_routing_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700610 7},
Amir Levy9659e592016-10-27 18:08:27 +0300611 [IPA_HW_v3_0][IPA_IMM_CMD_IP_V6_ROUTING_INIT] = {
612 ipa_imm_cmd_construct_ip_v6_routing_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700613 8},
Amir Levy9659e592016-10-27 18:08:27 +0300614 [IPA_HW_v3_0][IPA_IMM_CMD_HDR_INIT_LOCAL] = {
615 ipa_imm_cmd_construct_hdr_init_local,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700616 9},
Amir Levy9659e592016-10-27 18:08:27 +0300617 [IPA_HW_v3_0][IPA_IMM_CMD_HDR_INIT_SYSTEM] = {
618 ipa_imm_cmd_construct_hdr_init_system,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700619 10},
Amir Levy9659e592016-10-27 18:08:27 +0300620 [IPA_HW_v3_0][IPA_IMM_CMD_REGISTER_WRITE] = {
621 ipa_imm_cmd_construct_register_write,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700622 12},
Amir Levy9659e592016-10-27 18:08:27 +0300623 [IPA_HW_v3_0][IPA_IMM_CMD_NAT_DMA] = {
624 ipa_imm_cmd_construct_nat_dma,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700625 14},
Amir Levy9659e592016-10-27 18:08:27 +0300626 [IPA_HW_v3_0][IPA_IMM_CMD_IP_PACKET_INIT] = {
627 ipa_imm_cmd_construct_ip_packet_init,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700628 16},
Amir Levy9659e592016-10-27 18:08:27 +0300629 [IPA_HW_v3_0][IPA_IMM_CMD_DMA_TASK_32B_ADDR] = {
630 ipa_imm_cmd_construct_dma_task_32b_addr,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700631 17},
Amir Levy9659e592016-10-27 18:08:27 +0300632 [IPA_HW_v3_0][IPA_IMM_CMD_DMA_SHARED_MEM] = {
633 ipa_imm_cmd_construct_dma_shared_mem,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700634 19},
Amir Levy9659e592016-10-27 18:08:27 +0300635 [IPA_HW_v3_0][IPA_IMM_CMD_IP_PACKET_TAG_STATUS] = {
636 ipa_imm_cmd_construct_ip_packet_tag_status,
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700637 20},
638
639 /* IPAv4 */
640 [IPA_HW_v4_0][IPA_IMM_CMD_REGISTER_WRITE] = {
641 ipa_imm_cmd_construct_register_write_v_4_0,
642 12},
643 [IPA_HW_v4_0][IPA_IMM_CMD_DMA_SHARED_MEM] = {
644 ipa_imm_cmd_construct_dma_shared_mem_v_4_0,
645 19},
Amir Levy9659e592016-10-27 18:08:27 +0300646};
647
648/*
649 * ipahal_imm_cmd_init() - Build the Immediate command information table
650 * See ipahal_imm_cmd_objs[][] comments
651 */
652static int ipahal_imm_cmd_init(enum ipa_hw_type ipa_hw_type)
653{
654 int i;
655 int j;
656 struct ipahal_imm_cmd_obj zero_obj;
657
658 IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type);
659
660 if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) {
661 IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
662 return -EINVAL;
663 }
664
665 memset(&zero_obj, 0, sizeof(zero_obj));
666 for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; i++) {
667 for (j = 0; j < IPA_IMM_CMD_MAX ; j++) {
668 if (!memcmp(&ipahal_imm_cmd_objs[i+1][j], &zero_obj,
669 sizeof(struct ipahal_imm_cmd_obj))) {
670 memcpy(&ipahal_imm_cmd_objs[i+1][j],
671 &ipahal_imm_cmd_objs[i][j],
672 sizeof(struct ipahal_imm_cmd_obj));
673 } else {
674 /*
675 * explicitly overridden immediate command.
676 * Check validity
677 */
678 if (!ipahal_imm_cmd_objs[i+1][j].opcode) {
679 IPAHAL_ERR(
680 "imm_cmd=%s with zero opcode ipa_ver=%d\n",
681 ipahal_imm_cmd_name_str(j), i+1);
682 WARN_ON(1);
683 }
684 if (!ipahal_imm_cmd_objs[i+1][j].construct) {
685 IPAHAL_ERR(
686 "imm_cmd=%s with NULL construct func ipa_ver=%d\n",
687 ipahal_imm_cmd_name_str(j), i+1);
688 WARN_ON(1);
689 }
690 }
691 }
692 }
693
694 return 0;
695}
696
697/*
698 * ipahal_imm_cmd_name_str() - returns string that represent the imm cmd
699 * @cmd_name: [in] Immediate command name
700 */
701const char *ipahal_imm_cmd_name_str(enum ipahal_imm_cmd_name cmd_name)
702{
703 if (cmd_name < 0 || cmd_name >= IPA_IMM_CMD_MAX) {
704 IPAHAL_ERR("requested name of invalid imm_cmd=%d\n", cmd_name);
705 return "Invalid IMM_CMD";
706 }
707
708 return ipahal_imm_cmd_name_to_str[cmd_name];
709}
710
711/*
712 * ipahal_imm_cmd_get_opcode() - Get the fixed opcode of the immediate command
713 */
Michael Adisumartab5d170f2017-05-17 14:34:11 -0700714static u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd)
Amir Levy9659e592016-10-27 18:08:27 +0300715{
716 u32 opcode;
717
718 if (cmd >= IPA_IMM_CMD_MAX) {
719 IPAHAL_ERR("Invalid immediate command imm_cmd=%u\n", cmd);
720 ipa_assert();
721 return -EFAULT;
722 }
723
724 IPAHAL_DBG_LOW("Get opcode of IMM_CMD=%s\n",
725 ipahal_imm_cmd_name_str(cmd));
726 opcode = ipahal_imm_cmd_objs[ipahal_ctx->hw_type][cmd].opcode;
727 if (opcode == -1) {
728 IPAHAL_ERR("Try to get opcode of obsolete IMM_CMD=%s\n",
729 ipahal_imm_cmd_name_str(cmd));
730 ipa_assert();
731 return -EFAULT;
732 }
733
734 return opcode;
735}
736
737/*
Amir Levy9659e592016-10-27 18:08:27 +0300738 * ipahal_construct_imm_cmd() - Construct immdiate command
739 * This function builds imm cmd bulk that can be be sent to IPA
740 * The command will be allocated dynamically.
741 * After done using it, call ipahal_destroy_imm_cmd() to release it
742 */
743struct ipahal_imm_cmd_pyld *ipahal_construct_imm_cmd(
744 enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
745{
746 if (!params) {
747 IPAHAL_ERR("Input error: params=%p\n", params);
748 ipa_assert();
749 return NULL;
750 }
751
752 if (cmd >= IPA_IMM_CMD_MAX) {
753 IPAHAL_ERR("Invalid immediate command %u\n", cmd);
754 ipa_assert();
755 return NULL;
756 }
757
758 IPAHAL_DBG_LOW("construct IMM_CMD:%s\n", ipahal_imm_cmd_name_str(cmd));
759 return ipahal_imm_cmd_objs[ipahal_ctx->hw_type][cmd].construct(
760 cmd, params, is_atomic_ctx);
761}
762
763/*
764 * ipahal_construct_nop_imm_cmd() - Construct immediate comamnd for NO-Op
765 * Core driver may want functionality to inject NOP commands to IPA
766 * to ensure e.g., PIPLINE clear before someother operation.
767 * The functionality given by this function can be reached by
768 * ipahal_construct_imm_cmd(). This function is helper to the core driver
769 * to reach this NOP functionlity easily.
770 * @skip_pipline_clear: if to skip pipeline clear waiting (don't wait)
771 * @pipline_clr_opt: options for pipeline clear waiting
772 * @is_atomic_ctx: is called in atomic context or can sleep?
773 */
774struct ipahal_imm_cmd_pyld *ipahal_construct_nop_imm_cmd(
775 bool skip_pipline_clear,
776 enum ipahal_pipeline_clear_option pipline_clr_opt,
777 bool is_atomic_ctx)
778{
779 struct ipahal_imm_cmd_register_write cmd;
780 struct ipahal_imm_cmd_pyld *cmd_pyld;
781
782 memset(&cmd, 0, sizeof(cmd));
783 cmd.skip_pipeline_clear = skip_pipline_clear;
784 cmd.pipeline_clear_options = pipline_clr_opt;
785 cmd.value_mask = 0x0;
786
787 cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
788 &cmd, is_atomic_ctx);
789
790 if (!cmd_pyld)
791 IPAHAL_ERR("failed to construct register_write imm cmd\n");
792
793 return cmd_pyld;
794}
795
796
797/* IPA Packet Status Logic */
798
799#define IPA_PKT_STATUS_SET_MSK(__hw_bit_msk, __shft) \
800 (status->status_mask |= \
801 ((hw_status->status_mask & (__hw_bit_msk) ? 1 : 0) << (__shft)))
802
803static void ipa_pkt_status_parse(
804 const void *unparsed_status, struct ipahal_pkt_status *status)
805{
806 enum ipahal_pkt_status_opcode opcode = 0;
807 enum ipahal_pkt_status_exception exception_type = 0;
808
809 struct ipa_pkt_status_hw *hw_status =
810 (struct ipa_pkt_status_hw *)unparsed_status;
811
812 status->pkt_len = hw_status->pkt_len;
813 status->endp_src_idx = hw_status->endp_src_idx;
814 status->endp_dest_idx = hw_status->endp_dest_idx;
815 status->metadata = hw_status->metadata;
816 status->flt_local = hw_status->flt_local;
817 status->flt_hash = hw_status->flt_hash;
818 status->flt_global = hw_status->flt_hash;
819 status->flt_ret_hdr = hw_status->flt_ret_hdr;
820 status->flt_miss = ~(hw_status->flt_rule_id) ? false : true;
821 status->flt_rule_id = hw_status->flt_rule_id;
822 status->rt_local = hw_status->rt_local;
823 status->rt_hash = hw_status->rt_hash;
824 status->ucp = hw_status->ucp;
825 status->rt_tbl_idx = hw_status->rt_tbl_idx;
826 status->rt_miss = ~(hw_status->rt_rule_id) ? false : true;
827 status->rt_rule_id = hw_status->rt_rule_id;
828 status->nat_hit = hw_status->nat_hit;
829 status->nat_entry_idx = hw_status->nat_entry_idx;
830 status->tag_info = hw_status->tag_info;
831 status->seq_num = hw_status->seq_num;
832 status->time_of_day_ctr = hw_status->time_of_day_ctr;
833 status->hdr_local = hw_status->hdr_local;
834 status->hdr_offset = hw_status->hdr_offset;
835 status->frag_hit = hw_status->frag_hit;
836 status->frag_rule = hw_status->frag_rule;
837
838 switch (hw_status->status_opcode) {
839 case 0x1:
840 opcode = IPAHAL_PKT_STATUS_OPCODE_PACKET;
841 break;
842 case 0x2:
843 opcode = IPAHAL_PKT_STATUS_OPCODE_NEW_FRAG_RULE;
844 break;
845 case 0x4:
846 opcode = IPAHAL_PKT_STATUS_OPCODE_DROPPED_PACKET;
847 break;
848 case 0x8:
849 opcode = IPAHAL_PKT_STATUS_OPCODE_SUSPENDED_PACKET;
850 break;
851 case 0x10:
852 opcode = IPAHAL_PKT_STATUS_OPCODE_LOG;
853 break;
854 case 0x20:
855 opcode = IPAHAL_PKT_STATUS_OPCODE_DCMP;
856 break;
857 case 0x40:
858 opcode = IPAHAL_PKT_STATUS_OPCODE_PACKET_2ND_PASS;
859 break;
860 default:
861 IPAHAL_ERR("unsupported Status Opcode 0x%x\n",
862 hw_status->status_opcode);
863 WARN_ON(1);
864 };
865 status->status_opcode = opcode;
866
867 switch (hw_status->nat_type) {
868 case 0:
869 status->nat_type = IPAHAL_PKT_STATUS_NAT_NONE;
870 break;
871 case 1:
872 status->nat_type = IPAHAL_PKT_STATUS_NAT_SRC;
873 break;
874 case 2:
875 status->nat_type = IPAHAL_PKT_STATUS_NAT_DST;
876 break;
877 default:
878 IPAHAL_ERR("unsupported Status NAT type 0x%x\n",
879 hw_status->nat_type);
880 WARN_ON(1);
881 };
882
883 switch (hw_status->exception) {
884 case 0:
885 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_NONE;
886 break;
887 case 1:
888 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_DEAGGR;
889 break;
890 case 4:
891 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_IPTYPE;
892 break;
893 case 8:
894 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_PACKET_LENGTH;
895 break;
896 case 16:
897 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_FRAG_RULE_MISS;
898 break;
899 case 32:
900 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_SW_FILT;
901 break;
902 case 64:
903 exception_type = IPAHAL_PKT_STATUS_EXCEPTION_NAT;
904 break;
905 default:
906 IPAHAL_ERR("unsupported Status Exception type 0x%x\n",
907 hw_status->exception);
908 WARN_ON(1);
909 };
910 status->exception = exception_type;
911
912 IPA_PKT_STATUS_SET_MSK(0x1, IPAHAL_PKT_STATUS_MASK_FRAG_PROCESS_SHFT);
913 IPA_PKT_STATUS_SET_MSK(0x2, IPAHAL_PKT_STATUS_MASK_FILT_PROCESS_SHFT);
914 IPA_PKT_STATUS_SET_MSK(0x4, IPAHAL_PKT_STATUS_MASK_NAT_PROCESS_SHFT);
915 IPA_PKT_STATUS_SET_MSK(0x8, IPAHAL_PKT_STATUS_MASK_ROUTE_PROCESS_SHFT);
916 IPA_PKT_STATUS_SET_MSK(0x10, IPAHAL_PKT_STATUS_MASK_TAG_VALID_SHFT);
917 IPA_PKT_STATUS_SET_MSK(0x20, IPAHAL_PKT_STATUS_MASK_FRAGMENT_SHFT);
918 IPA_PKT_STATUS_SET_MSK(0x40,
919 IPAHAL_PKT_STATUS_MASK_FIRST_FRAGMENT_SHFT);
920 IPA_PKT_STATUS_SET_MSK(0x80, IPAHAL_PKT_STATUS_MASK_V4_SHFT);
921 IPA_PKT_STATUS_SET_MSK(0x100,
922 IPAHAL_PKT_STATUS_MASK_CKSUM_PROCESS_SHFT);
923 IPA_PKT_STATUS_SET_MSK(0x200, IPAHAL_PKT_STATUS_MASK_AGGR_PROCESS_SHFT);
924 IPA_PKT_STATUS_SET_MSK(0x400, IPAHAL_PKT_STATUS_MASK_DEST_EOT_SHFT);
925 IPA_PKT_STATUS_SET_MSK(0x800,
926 IPAHAL_PKT_STATUS_MASK_DEAGGR_PROCESS_SHFT);
927 IPA_PKT_STATUS_SET_MSK(0x1000, IPAHAL_PKT_STATUS_MASK_DEAGG_FIRST_SHFT);
928 IPA_PKT_STATUS_SET_MSK(0x2000, IPAHAL_PKT_STATUS_MASK_SRC_EOT_SHFT);
929 IPA_PKT_STATUS_SET_MSK(0x4000, IPAHAL_PKT_STATUS_MASK_PREV_EOT_SHFT);
930 IPA_PKT_STATUS_SET_MSK(0x8000, IPAHAL_PKT_STATUS_MASK_BYTE_LIMIT_SHFT);
931 status->status_mask &= 0xFFFF;
932}
933
934/*
935 * struct ipahal_pkt_status_obj - Pakcet Status H/W information for
936 * specific IPA version
937 * @size: H/W size of the status packet
938 * @parse: CB that parses the H/W packet status into the abstracted structure
939 */
940struct ipahal_pkt_status_obj {
941 u32 size;
942 void (*parse)(const void *unparsed_status,
943 struct ipahal_pkt_status *status);
944};
945
946/*
947 * This table contains the info regard packet status for IPAv3 and later
948 * Information like: size of packet status and parsing function
949 * All the information on the pkt Status on IPAv3 are statically defined below.
950 * If information is missing regard some IPA version, the init function
951 * will fill it with the information from the previous IPA version.
952 * Information is considered missing if all of the fields are 0
953 */
954static struct ipahal_pkt_status_obj ipahal_pkt_status_objs[IPA_HW_MAX] = {
955 /* IPAv3 */
956 [IPA_HW_v3_0] = {
957 IPA3_0_PKT_STATUS_SIZE,
958 ipa_pkt_status_parse,
959 },
960};
961
962/*
963 * ipahal_pkt_status_init() - Build the packet status information array
964 * for the different IPA versions
965 * See ipahal_pkt_status_objs[] comments
966 */
967static int ipahal_pkt_status_init(enum ipa_hw_type ipa_hw_type)
968{
969 int i;
970 struct ipahal_pkt_status_obj zero_obj;
971
972 IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type);
973
974 if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) {
975 IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
976 return -EINVAL;
977 }
978
979 /*
980 * Since structure alignment is implementation dependent,
981 * add test to avoid different and incompatible data layouts.
982 *
983 * In case new H/W has different size or structure of status packet,
984 * add a compile time validty check for it like below (as well as
985 * the new defines and/or the new strucutre in the internal header).
986 */
987 BUILD_BUG_ON(sizeof(struct ipa_pkt_status_hw) !=
988 IPA3_0_PKT_STATUS_SIZE);
989
990 memset(&zero_obj, 0, sizeof(zero_obj));
991 for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; i++) {
992 if (!memcmp(&ipahal_pkt_status_objs[i+1], &zero_obj,
993 sizeof(struct ipahal_pkt_status_obj))) {
994 memcpy(&ipahal_pkt_status_objs[i+1],
995 &ipahal_pkt_status_objs[i],
996 sizeof(struct ipahal_pkt_status_obj));
997 } else {
998 /*
999 * explicitly overridden Packet Status info
1000 * Check validity
1001 */
1002 if (!ipahal_pkt_status_objs[i+1].size) {
1003 IPAHAL_ERR(
1004 "Packet Status with zero size ipa_ver=%d\n",
1005 i+1);
1006 WARN_ON(1);
1007 }
1008 if (!ipahal_pkt_status_objs[i+1].parse) {
1009 IPAHAL_ERR(
1010 "Packet Status without Parse func ipa_ver=%d\n",
1011 i+1);
1012 WARN_ON(1);
1013 }
1014 }
1015 }
1016
1017 return 0;
1018}
1019
1020/*
1021 * ipahal_pkt_status_get_size() - Get H/W size of packet status
1022 */
1023u32 ipahal_pkt_status_get_size(void)
1024{
1025 return ipahal_pkt_status_objs[ipahal_ctx->hw_type].size;
1026}
1027
1028/*
1029 * ipahal_pkt_status_parse() - Parse Packet Status payload to abstracted form
1030 * @unparsed_status: Pointer to H/W format of the packet status as read from H/W
1031 * @status: Pointer to pre-allocated buffer where the parsed info will be stored
1032 */
1033void ipahal_pkt_status_parse(const void *unparsed_status,
1034 struct ipahal_pkt_status *status)
1035{
1036 if (!unparsed_status || !status) {
1037 IPAHAL_ERR("Input Error: unparsed_status=%p status=%p\n",
1038 unparsed_status, status);
1039 return;
1040 }
1041
1042 IPAHAL_DBG_LOW("Parse Status Packet\n");
1043 memset(status, 0, sizeof(*status));
1044 ipahal_pkt_status_objs[ipahal_ctx->hw_type].parse(unparsed_status,
1045 status);
1046}
1047
1048/*
1049 * ipahal_pkt_status_exception_str() - returns string represents exception type
1050 * @exception: [in] The exception type
1051 */
1052const char *ipahal_pkt_status_exception_str(
1053 enum ipahal_pkt_status_exception exception)
1054{
1055 if (exception < 0 || exception >= IPAHAL_PKT_STATUS_EXCEPTION_MAX) {
1056 IPAHAL_ERR(
1057 "requested string of invalid pkt_status exception=%d\n",
1058 exception);
1059 return "Invalid PKT_STATUS_EXCEPTION";
1060 }
1061
1062 return ipahal_pkt_status_exception_to_str[exception];
1063}
1064
1065#ifdef CONFIG_DEBUG_FS
1066static void ipahal_debugfs_init(void)
1067{
1068 ipahal_ctx->dent = debugfs_create_dir("ipahal", 0);
1069 if (!ipahal_ctx->dent || IS_ERR(ipahal_ctx->dent)) {
1070 IPAHAL_ERR("fail to create ipahal debugfs folder\n");
1071 goto fail;
1072 }
1073
1074 return;
1075fail:
1076 debugfs_remove_recursive(ipahal_ctx->dent);
1077 ipahal_ctx->dent = NULL;
1078}
1079
1080static void ipahal_debugfs_remove(void)
1081{
1082 if (!ipahal_ctx)
1083 return;
1084
1085 if (IS_ERR(ipahal_ctx->dent)) {
1086 IPAHAL_ERR("ipahal debugfs folder was not created\n");
1087 return;
1088 }
1089
1090 debugfs_remove_recursive(ipahal_ctx->dent);
1091}
1092#else /* CONFIG_DEBUG_FS */
1093static void ipahal_debugfs_init(void) {}
1094static void ipahal_debugfs_remove(void) {}
1095#endif /* CONFIG_DEBUG_FS */
1096
1097/*
1098 * ipahal_cp_hdr_to_hw_buff_v3() - copy header to hardware buffer according to
1099 * base address and offset given.
1100 * @base: dma base address
1101 * @offset: offset from base address where the data will be copied
1102 * @hdr: the header to be copied
1103 * @hdr_len: the length of the header
1104 */
1105static void ipahal_cp_hdr_to_hw_buff_v3(void *const base, u32 offset,
1106 u8 *const hdr, u32 hdr_len)
1107{
1108 memcpy(base + offset, hdr, hdr_len);
1109}
1110
1111/*
1112 * ipahal_cp_proc_ctx_to_hw_buff_v3() - copy processing context to
1113 * base address and offset given.
1114 * @type: header processing context type (no processing context,
1115 * IPA_HDR_PROC_ETHII_TO_ETHII etc.)
1116 * @base: dma base address
1117 * @offset: offset from base address where the data will be copied
1118 * @hdr_len: the length of the header
1119 * @is_hdr_proc_ctx: header is located in phys_base (true) or hdr_base_addr
1120 * @phys_base: memory location in DDR
1121 * @hdr_base_addr: base address in table
1122 * @offset_entry: offset from hdr_base_addr in table
1123 */
1124static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type,
1125 void *const base, u32 offset,
1126 u32 hdr_len, bool is_hdr_proc_ctx,
1127 dma_addr_t phys_base, u32 hdr_base_addr,
1128 struct ipa_hdr_offset_entry *offset_entry){
1129 if (type == IPA_HDR_PROC_NONE) {
1130 struct ipa_hw_hdr_proc_ctx_add_hdr_seq *ctx;
1131
1132 ctx = (struct ipa_hw_hdr_proc_ctx_add_hdr_seq *)
1133 (base + offset);
1134 ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD;
1135 ctx->hdr_add.tlv.length = 1;
1136 ctx->hdr_add.tlv.value = hdr_len;
1137 ctx->hdr_add.hdr_addr = is_hdr_proc_ctx ? phys_base :
1138 hdr_base_addr + offset_entry->offset;
1139 IPAHAL_DBG("header address 0x%x\n",
1140 ctx->hdr_add.hdr_addr);
1141 ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
1142 ctx->end.length = 0;
1143 ctx->end.value = 0;
1144 } else {
1145 struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq *ctx;
1146
1147 ctx = (struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq *)
1148 (base + offset);
1149 ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD;
1150 ctx->hdr_add.tlv.length = 1;
1151 ctx->hdr_add.tlv.value = hdr_len;
1152 ctx->hdr_add.hdr_addr = is_hdr_proc_ctx ? phys_base :
1153 hdr_base_addr + offset_entry->offset;
1154 IPAHAL_DBG("header address 0x%x\n",
1155 ctx->hdr_add.hdr_addr);
1156 ctx->cmd.type = IPA_PROC_CTX_TLV_TYPE_PROC_CMD;
1157 ctx->cmd.length = 0;
1158 switch (type) {
1159 case IPA_HDR_PROC_ETHII_TO_ETHII:
1160 ctx->cmd.value = IPA_HDR_UCP_ETHII_TO_ETHII;
1161 break;
1162 case IPA_HDR_PROC_ETHII_TO_802_3:
1163 ctx->cmd.value = IPA_HDR_UCP_ETHII_TO_802_3;
1164 break;
1165 case IPA_HDR_PROC_802_3_TO_ETHII:
1166 ctx->cmd.value = IPA_HDR_UCP_802_3_TO_ETHII;
1167 break;
1168 case IPA_HDR_PROC_802_3_TO_802_3:
1169 ctx->cmd.value = IPA_HDR_UCP_802_3_TO_802_3;
1170 break;
1171 default:
1172 IPAHAL_ERR("unknown ipa_hdr_proc_type %d", type);
1173 WARN_ON(1);
1174 return -EINVAL;
1175 }
1176 IPAHAL_DBG("command id %d\n", ctx->cmd.value);
1177 ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
1178 ctx->end.length = 0;
1179 ctx->end.value = 0;
1180 }
1181
1182 return 0;
1183}
1184
1185/*
1186 * ipahal_get_proc_ctx_needed_len_v3() - calculates the needed length for
1187 * addition of header processing context according to the type of processing
1188 * context.
1189 * @type: header processing context type (no processing context,
1190 * IPA_HDR_PROC_ETHII_TO_ETHII etc.)
1191 */
1192static int ipahal_get_proc_ctx_needed_len_v3(enum ipa_hdr_proc_type type)
1193{
1194 return (type == IPA_HDR_PROC_NONE) ?
1195 sizeof(struct ipa_hw_hdr_proc_ctx_add_hdr_seq) :
1196 sizeof(struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq);
1197}
1198
1199/*
1200 * struct ipahal_hdr_funcs - headers handling functions for specific IPA
1201 * version
1202 * @ipahal_cp_hdr_to_hw_buff - copy function for regular headers
1203 */
1204struct ipahal_hdr_funcs {
1205 void (*ipahal_cp_hdr_to_hw_buff)(void *const base, u32 offset,
1206 u8 *const hdr, u32 hdr_len);
1207
1208 int (*ipahal_cp_proc_ctx_to_hw_buff)(enum ipa_hdr_proc_type type,
1209 void *const base, u32 offset, u32 hdr_len,
1210 bool is_hdr_proc_ctx, dma_addr_t phys_base,
1211 u32 hdr_base_addr,
1212 struct ipa_hdr_offset_entry *offset_entry);
1213
1214 int (*ipahal_get_proc_ctx_needed_len)(enum ipa_hdr_proc_type type);
1215};
1216
1217static struct ipahal_hdr_funcs hdr_funcs;
1218
1219static void ipahal_hdr_init(enum ipa_hw_type ipa_hw_type)
1220{
1221
1222 IPAHAL_DBG("Entry - HW_TYPE=%d\n", ipa_hw_type);
1223
1224 /*
1225 * once there are changes in HW and need to use different case, insert
1226 * new case for the new h/w. put the default always for the latest HW
1227 * and make sure all previous supported versions have their cases.
1228 */
1229 switch (ipa_hw_type) {
1230 case IPA_HW_v3_0:
1231 default:
1232 hdr_funcs.ipahal_cp_hdr_to_hw_buff =
1233 ipahal_cp_hdr_to_hw_buff_v3;
1234 hdr_funcs.ipahal_cp_proc_ctx_to_hw_buff =
1235 ipahal_cp_proc_ctx_to_hw_buff_v3;
1236 hdr_funcs.ipahal_get_proc_ctx_needed_len =
1237 ipahal_get_proc_ctx_needed_len_v3;
1238 }
1239 IPAHAL_DBG("Exit\n");
1240}
1241
1242/*
1243 * ipahal_cp_hdr_to_hw_buff() - copy header to hardware buffer according to
1244 * base address and offset given.
1245 * @base: dma base address
1246 * @offset: offset from base address where the data will be copied
1247 * @hdr: the header to be copied
1248 * @hdr_len: the length of the header
1249 */
1250void ipahal_cp_hdr_to_hw_buff(void *base, u32 offset, u8 *const hdr,
1251 u32 hdr_len)
1252{
1253 IPAHAL_DBG_LOW("Entry\n");
1254 IPAHAL_DBG("base %p, offset %d, hdr %p, hdr_len %d\n", base,
1255 offset, hdr, hdr_len);
1256 if (!base || !hdr_len || !hdr) {
1257 IPAHAL_ERR("failed on validating params");
1258 return;
1259 }
1260
1261 hdr_funcs.ipahal_cp_hdr_to_hw_buff(base, offset, hdr, hdr_len);
1262
1263 IPAHAL_DBG_LOW("Exit\n");
1264}
1265
1266/*
1267 * ipahal_cp_proc_ctx_to_hw_buff() - copy processing context to
1268 * base address and offset given.
1269 * @type: type of header processing context
1270 * @base: dma base address
1271 * @offset: offset from base address where the data will be copied
1272 * @hdr_len: the length of the header
1273 * @is_hdr_proc_ctx: header is located in phys_base (true) or hdr_base_addr
1274 * @phys_base: memory location in DDR
1275 * @hdr_base_addr: base address in table
1276 * @offset_entry: offset from hdr_base_addr in table
1277 */
1278int ipahal_cp_proc_ctx_to_hw_buff(enum ipa_hdr_proc_type type,
1279 void *const base, u32 offset, u32 hdr_len,
1280 bool is_hdr_proc_ctx, dma_addr_t phys_base,
1281 u32 hdr_base_addr, struct ipa_hdr_offset_entry *offset_entry)
1282{
1283 IPAHAL_DBG(
1284 "type %d, base %p, offset %d, hdr_len %d, is_hdr_proc_ctx %d, hdr_base_addr %d, offset_entry %p\n"
1285 , type, base, offset, hdr_len, is_hdr_proc_ctx,
1286 hdr_base_addr, offset_entry);
1287
1288 if (!base ||
1289 !hdr_len ||
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001290 (is_hdr_proc_ctx && !phys_base) ||
1291 (!is_hdr_proc_ctx && !offset_entry) ||
1292 (!is_hdr_proc_ctx && !hdr_base_addr)) {
Amir Levy9659e592016-10-27 18:08:27 +03001293 IPAHAL_ERR(
1294 "invalid input: hdr_len:%u phys_base:%pad hdr_base_addr:%u is_hdr_proc_ctx:%d offset_entry:%pK\n"
1295 , hdr_len, &phys_base, hdr_base_addr
1296 , is_hdr_proc_ctx, offset_entry);
1297 return -EINVAL;
1298 }
1299
1300 return hdr_funcs.ipahal_cp_proc_ctx_to_hw_buff(type, base, offset,
1301 hdr_len, is_hdr_proc_ctx, phys_base,
1302 hdr_base_addr, offset_entry);
1303}
1304
1305/*
1306 * ipahal_get_proc_ctx_needed_len() - calculates the needed length for
1307 * addition of header processing context according to the type of processing
1308 * context
1309 * @type: header processing context type (no processing context,
1310 * IPA_HDR_PROC_ETHII_TO_ETHII etc.)
1311 */
1312int ipahal_get_proc_ctx_needed_len(enum ipa_hdr_proc_type type)
1313{
1314 int res;
1315
1316 IPAHAL_DBG("entry\n");
1317
1318 res = hdr_funcs.ipahal_get_proc_ctx_needed_len(type);
1319
1320 IPAHAL_DBG("Exit\n");
1321
1322 return res;
1323}
1324
Ghanim Fodi37b64952017-01-24 15:42:30 +02001325/*
1326 * Get IPA Data Processing Star image memory size at IPA SRAM
1327 */
1328u32 ipahal_get_dps_img_mem_size(void)
1329{
1330 return IPA_HW_DPS_IMG_MEM_SIZE_V3_0;
1331}
1332
1333/*
1334 * Get IPA Header Processing Star image memory size at IPA SRAM
1335 */
1336u32 ipahal_get_hps_img_mem_size(void)
1337{
1338 return IPA_HW_HPS_IMG_MEM_SIZE_V3_0;
1339}
Amir Levy9659e592016-10-27 18:08:27 +03001340
1341int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base,
1342 struct device *ipa_pdev)
1343{
1344 int result;
1345
1346 IPAHAL_DBG("Entry - IPA HW TYPE=%d base=%p ipa_pdev=%p\n",
1347 ipa_hw_type, base, ipa_pdev);
1348
1349 ipahal_ctx = kzalloc(sizeof(*ipahal_ctx), GFP_KERNEL);
1350 if (!ipahal_ctx) {
1351 IPAHAL_ERR("kzalloc err for ipahal_ctx\n");
1352 result = -ENOMEM;
1353 goto bail_err_exit;
1354 }
1355
1356 if (ipa_hw_type < IPA_HW_v3_0) {
1357 IPAHAL_ERR("ipahal supported on IPAv3 and later only\n");
1358 result = -EINVAL;
1359 goto bail_free_ctx;
1360 }
1361
1362 if (ipa_hw_type >= IPA_HW_MAX) {
1363 IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
1364 result = -EINVAL;
1365 goto bail_free_ctx;
1366 }
1367
1368 if (!base) {
1369 IPAHAL_ERR("invalid memory io mapping addr\n");
1370 result = -EINVAL;
1371 goto bail_free_ctx;
1372 }
1373
1374 if (!ipa_pdev) {
1375 IPAHAL_ERR("invalid IPA platform device\n");
1376 result = -EINVAL;
1377 goto bail_free_ctx;
1378 }
1379
1380 ipahal_ctx->hw_type = ipa_hw_type;
1381 ipahal_ctx->base = base;
1382 ipahal_ctx->ipa_pdev = ipa_pdev;
1383
1384 if (ipahal_reg_init(ipa_hw_type)) {
1385 IPAHAL_ERR("failed to init ipahal reg\n");
1386 result = -EFAULT;
1387 goto bail_free_ctx;
1388 }
1389
1390 if (ipahal_imm_cmd_init(ipa_hw_type)) {
1391 IPAHAL_ERR("failed to init ipahal imm cmd\n");
1392 result = -EFAULT;
1393 goto bail_free_ctx;
1394 }
1395
1396 if (ipahal_pkt_status_init(ipa_hw_type)) {
1397 IPAHAL_ERR("failed to init ipahal pkt status\n");
1398 result = -EFAULT;
1399 goto bail_free_ctx;
1400 }
1401
1402 ipahal_hdr_init(ipa_hw_type);
1403
1404 if (ipahal_fltrt_init(ipa_hw_type)) {
1405 IPAHAL_ERR("failed to init ipahal flt rt\n");
1406 result = -EFAULT;
1407 goto bail_free_ctx;
1408 }
1409
1410 ipahal_debugfs_init();
1411
1412 return 0;
1413
1414bail_free_ctx:
1415 kfree(ipahal_ctx);
1416 ipahal_ctx = NULL;
1417bail_err_exit:
1418 return result;
1419}
1420
1421void ipahal_destroy(void)
1422{
1423 IPAHAL_DBG("Entry\n");
1424 ipahal_fltrt_destroy();
1425 ipahal_debugfs_remove();
1426 kfree(ipahal_ctx);
1427 ipahal_ctx = NULL;
1428}
1429
1430void ipahal_free_dma_mem(struct ipa_mem_buffer *mem)
1431{
1432 if (likely(mem)) {
1433 dma_free_coherent(ipahal_ctx->ipa_pdev, mem->size, mem->base,
1434 mem->phys_base);
1435 mem->size = 0;
1436 mem->base = NULL;
1437 mem->phys_base = 0;
1438 }
1439}