1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* Applied Micro X-Gene SoC Ethernet Classifier structures |
3 | * |
4 | * Copyright (c) 2016, Applied Micro Circuits Corporation |
5 | * Authors: Khuong Dinh <kdinh@apm.com> |
6 | * Tanmay Inamdar <tinamdar@apm.com> |
7 | * Iyappan Subramanian <isubramanian@apm.com> |
8 | */ |
9 | |
10 | #include "xgene_enet_main.h" |
11 | |
12 | /* interfaces to convert structures to HW recognized bit formats */ |
13 | static void xgene_cle_sband_to_hw(u8 frag, enum xgene_cle_prot_version ver, |
14 | enum xgene_cle_prot_type type, u32 len, |
15 | u32 *reg) |
16 | { |
17 | *reg = SET_VAL(SB_IPFRAG, frag) | |
18 | SET_VAL(SB_IPPROT, type) | |
19 | SET_VAL(SB_IPVER, ver) | |
20 | SET_VAL(SB_HDRLEN, len); |
21 | } |
22 | |
23 | static void xgene_cle_idt_to_hw(struct xgene_enet_pdata *pdata, |
24 | u32 dstqid, u32 fpsel, |
25 | u32 nfpsel, u32 *idt_reg) |
26 | { |
27 | if (pdata->enet_id == XGENE_ENET1) { |
28 | *idt_reg = SET_VAL(IDT_DSTQID, dstqid) | |
29 | SET_VAL(IDT_FPSEL1, fpsel) | |
30 | SET_VAL(IDT_NFPSEL1, nfpsel); |
31 | } else { |
32 | *idt_reg = SET_VAL(IDT_DSTQID, dstqid) | |
33 | SET_VAL(IDT_FPSEL, fpsel) | |
34 | SET_VAL(IDT_NFPSEL, nfpsel); |
35 | } |
36 | } |
37 | |
38 | static void xgene_cle_dbptr_to_hw(struct xgene_enet_pdata *pdata, |
39 | struct xgene_cle_dbptr *dbptr, u32 *buf) |
40 | { |
41 | buf[0] = SET_VAL(CLE_DROP, dbptr->drop); |
42 | buf[4] = SET_VAL(CLE_FPSEL, dbptr->fpsel) | |
43 | SET_VAL(CLE_NFPSEL, dbptr->nxtfpsel) | |
44 | SET_VAL(CLE_DSTQIDL, dbptr->dstqid); |
45 | |
46 | buf[5] = SET_VAL(CLE_DSTQIDH, (u32)dbptr->dstqid >> CLE_DSTQIDL_LEN) | |
47 | SET_VAL(CLE_PRIORITY, dbptr->cle_priority); |
48 | } |
49 | |
50 | static void xgene_cle_kn_to_hw(struct xgene_cle_ptree_kn *kn, u32 *buf) |
51 | { |
52 | u32 i, j = 0; |
53 | u32 data; |
54 | |
55 | buf[j++] = SET_VAL(CLE_TYPE, kn->node_type); |
56 | for (i = 0; i < kn->num_keys; i++) { |
57 | struct xgene_cle_ptree_key *key = &kn->key[i]; |
58 | |
59 | if (!(i % 2)) { |
60 | buf[j] = SET_VAL(CLE_KN_PRIO, key->priority) | |
61 | SET_VAL(CLE_KN_RPTR, key->result_pointer); |
62 | } else { |
63 | data = SET_VAL(CLE_KN_PRIO, key->priority) | |
64 | SET_VAL(CLE_KN_RPTR, key->result_pointer); |
65 | buf[j++] |= (data << 16); |
66 | } |
67 | } |
68 | } |
69 | |
70 | static void xgene_cle_dn_to_hw(const struct xgene_cle_ptree_ewdn *dn, |
71 | u32 *buf, u32 jb) |
72 | { |
73 | const struct xgene_cle_ptree_branch *br; |
74 | u32 i, j = 0; |
75 | u32 npp; |
76 | |
77 | buf[j++] = SET_VAL(CLE_DN_TYPE, dn->node_type) | |
78 | SET_VAL(CLE_DN_LASTN, dn->last_node) | |
79 | SET_VAL(CLE_DN_HLS, dn->hdr_len_store) | |
80 | SET_VAL(CLE_DN_EXT, dn->hdr_extn) | |
81 | SET_VAL(CLE_DN_BSTOR, dn->byte_store) | |
82 | SET_VAL(CLE_DN_SBSTOR, dn->search_byte_store) | |
83 | SET_VAL(CLE_DN_RPTR, dn->result_pointer); |
84 | |
85 | for (i = 0; i < dn->num_branches; i++) { |
86 | br = &dn->branch[i]; |
87 | npp = br->next_packet_pointer; |
88 | |
89 | if ((br->jump_rel == JMP_ABS) && (npp < CLE_PKTRAM_SIZE)) |
90 | npp += jb; |
91 | |
92 | buf[j++] = SET_VAL(CLE_BR_VALID, br->valid) | |
93 | SET_VAL(CLE_BR_NPPTR, npp) | |
94 | SET_VAL(CLE_BR_JB, br->jump_bw) | |
95 | SET_VAL(CLE_BR_JR, br->jump_rel) | |
96 | SET_VAL(CLE_BR_OP, br->operation) | |
97 | SET_VAL(CLE_BR_NNODE, br->next_node) | |
98 | SET_VAL(CLE_BR_NBR, br->next_branch); |
99 | |
100 | buf[j++] = SET_VAL(CLE_BR_DATA, br->data) | |
101 | SET_VAL(CLE_BR_MASK, br->mask); |
102 | } |
103 | } |
104 | |
105 | static int xgene_cle_poll_cmd_done(void __iomem *base, |
106 | enum xgene_cle_cmd_type cmd) |
107 | { |
108 | u32 status, loop = 10; |
109 | int ret = -EBUSY; |
110 | |
111 | while (loop--) { |
112 | status = ioread32(base + INDCMD_STATUS); |
113 | if (status & cmd) { |
114 | ret = 0; |
115 | break; |
116 | } |
117 | usleep_range(min: 1000, max: 2000); |
118 | } |
119 | |
120 | return ret; |
121 | } |
122 | |
123 | static int xgene_cle_dram_wr(struct xgene_enet_cle *cle, u32 *data, u8 nregs, |
124 | u32 index, enum xgene_cle_dram_type type, |
125 | enum xgene_cle_cmd_type cmd) |
126 | { |
127 | enum xgene_cle_parser parser = cle->active_parser; |
128 | void __iomem *base = cle->base; |
129 | u32 i, j, ind_addr; |
130 | u8 port, nparsers; |
131 | int ret = 0; |
132 | |
133 | /* PTREE_RAM onwards, DRAM regions are common for all parsers */ |
134 | nparsers = (type >= PTREE_RAM) ? 1 : cle->parsers; |
135 | |
136 | for (i = 0; i < nparsers; i++) { |
137 | port = i; |
138 | if ((type < PTREE_RAM) && (parser != PARSER_ALL)) |
139 | port = parser; |
140 | |
141 | ind_addr = XGENE_CLE_DRAM(type + (port * 4)) | index; |
142 | iowrite32(ind_addr, base + INDADDR); |
143 | for (j = 0; j < nregs; j++) |
144 | iowrite32(data[j], base + DATA_RAM0 + (j * 4)); |
145 | iowrite32(cmd, base + INDCMD); |
146 | |
147 | ret = xgene_cle_poll_cmd_done(base, cmd); |
148 | if (ret) |
149 | break; |
150 | } |
151 | |
152 | return ret; |
153 | } |
154 | |
155 | static void xgene_cle_enable_ptree(struct xgene_enet_pdata *pdata, |
156 | struct xgene_enet_cle *cle) |
157 | { |
158 | struct xgene_cle_ptree *ptree = &cle->ptree; |
159 | void __iomem *addr, *base = cle->base; |
160 | u32 offset = CLE_PORT_OFFSET; |
161 | u32 i; |
162 | |
163 | /* 1G port has to advance 4 bytes and 10G has to advance 8 bytes */ |
164 | ptree->start_pkt += cle->jump_bytes; |
165 | for (i = 0; i < cle->parsers; i++) { |
166 | if (cle->active_parser != PARSER_ALL) |
167 | addr = base + cle->active_parser * offset; |
168 | else |
169 | addr = base + (i * offset); |
170 | |
171 | iowrite32(ptree->start_node & 0x3fff, addr + SNPTR0); |
172 | iowrite32(ptree->start_pkt & 0x1ff, addr + SPPTR0); |
173 | } |
174 | } |
175 | |
176 | static int xgene_cle_setup_dbptr(struct xgene_enet_pdata *pdata, |
177 | struct xgene_enet_cle *cle) |
178 | { |
179 | struct xgene_cle_ptree *ptree = &cle->ptree; |
180 | u32 buf[CLE_DRAM_REGS]; |
181 | u32 i; |
182 | int ret; |
183 | |
184 | memset(buf, 0, sizeof(buf)); |
185 | for (i = 0; i < ptree->num_dbptr; i++) { |
186 | xgene_cle_dbptr_to_hw(pdata, dbptr: &ptree->dbptr[i], buf); |
187 | ret = xgene_cle_dram_wr(cle, data: buf, nregs: 6, index: i + ptree->start_dbptr, |
188 | type: DB_RAM, cmd: CLE_CMD_WR); |
189 | if (ret) |
190 | return ret; |
191 | } |
192 | |
193 | return 0; |
194 | } |
195 | |
196 | static const struct xgene_cle_ptree_ewdn xgene_init_ptree_dn[] = { |
197 | { |
198 | /* PKT_TYPE_NODE */ |
199 | .node_type = EWDN, |
200 | .last_node = 0, |
201 | .hdr_len_store = 1, |
202 | .hdr_extn = NO_BYTE, |
203 | .byte_store = NO_BYTE, |
204 | .search_byte_store = NO_BYTE, |
205 | .result_pointer = DB_RES_DROP, |
206 | .num_branches = 2, |
207 | .branch = { |
208 | { |
209 | /* IPV4 */ |
210 | .valid = 1, |
211 | .next_packet_pointer = 22, |
212 | .jump_bw = JMP_FW, |
213 | .jump_rel = JMP_ABS, |
214 | .operation = EQT, |
215 | .next_node = PKT_PROT_NODE, |
216 | .next_branch = 0, |
217 | .data = 0x8, |
218 | .mask = 0x0 |
219 | }, |
220 | { |
221 | .valid = 0, |
222 | .next_packet_pointer = 262, |
223 | .jump_bw = JMP_FW, |
224 | .jump_rel = JMP_ABS, |
225 | .operation = EQT, |
226 | .next_node = LAST_NODE, |
227 | .next_branch = 0, |
228 | .data = 0x0, |
229 | .mask = 0xffff |
230 | } |
231 | }, |
232 | }, |
233 | { |
234 | /* PKT_PROT_NODE */ |
235 | .node_type = EWDN, |
236 | .last_node = 0, |
237 | .hdr_len_store = 1, |
238 | .hdr_extn = NO_BYTE, |
239 | .byte_store = NO_BYTE, |
240 | .search_byte_store = NO_BYTE, |
241 | .result_pointer = DB_RES_DROP, |
242 | .num_branches = 3, |
243 | .branch = { |
244 | { |
245 | /* TCP */ |
246 | .valid = 1, |
247 | .next_packet_pointer = 26, |
248 | .jump_bw = JMP_FW, |
249 | .jump_rel = JMP_ABS, |
250 | .operation = EQT, |
251 | .next_node = RSS_IPV4_TCP_NODE, |
252 | .next_branch = 0, |
253 | .data = 0x0600, |
254 | .mask = 0x00ff |
255 | }, |
256 | { |
257 | /* UDP */ |
258 | .valid = 1, |
259 | .next_packet_pointer = 26, |
260 | .jump_bw = JMP_FW, |
261 | .jump_rel = JMP_ABS, |
262 | .operation = EQT, |
263 | .next_node = RSS_IPV4_UDP_NODE, |
264 | .next_branch = 0, |
265 | .data = 0x1100, |
266 | .mask = 0x00ff |
267 | }, |
268 | { |
269 | .valid = 0, |
270 | .next_packet_pointer = 26, |
271 | .jump_bw = JMP_FW, |
272 | .jump_rel = JMP_ABS, |
273 | .operation = EQT, |
274 | .next_node = RSS_IPV4_OTHERS_NODE, |
275 | .next_branch = 0, |
276 | .data = 0x0, |
277 | .mask = 0xffff |
278 | } |
279 | } |
280 | }, |
281 | { |
282 | /* RSS_IPV4_TCP_NODE */ |
283 | .node_type = EWDN, |
284 | .last_node = 0, |
285 | .hdr_len_store = 1, |
286 | .hdr_extn = NO_BYTE, |
287 | .byte_store = NO_BYTE, |
288 | .search_byte_store = BOTH_BYTES, |
289 | .result_pointer = DB_RES_DROP, |
290 | .num_branches = 6, |
291 | .branch = { |
292 | { |
293 | /* SRC IPV4 B01 */ |
294 | .valid = 0, |
295 | .next_packet_pointer = 28, |
296 | .jump_bw = JMP_FW, |
297 | .jump_rel = JMP_ABS, |
298 | .operation = EQT, |
299 | .next_node = RSS_IPV4_TCP_NODE, |
300 | .next_branch = 1, |
301 | .data = 0x0, |
302 | .mask = 0xffff |
303 | }, |
304 | { |
305 | /* SRC IPV4 B23 */ |
306 | .valid = 0, |
307 | .next_packet_pointer = 30, |
308 | .jump_bw = JMP_FW, |
309 | .jump_rel = JMP_ABS, |
310 | .operation = EQT, |
311 | .next_node = RSS_IPV4_TCP_NODE, |
312 | .next_branch = 2, |
313 | .data = 0x0, |
314 | .mask = 0xffff |
315 | }, |
316 | { |
317 | /* DST IPV4 B01 */ |
318 | .valid = 0, |
319 | .next_packet_pointer = 32, |
320 | .jump_bw = JMP_FW, |
321 | .jump_rel = JMP_ABS, |
322 | .operation = EQT, |
323 | .next_node = RSS_IPV4_TCP_NODE, |
324 | .next_branch = 3, |
325 | .data = 0x0, |
326 | .mask = 0xffff |
327 | }, |
328 | { |
329 | /* DST IPV4 B23 */ |
330 | .valid = 0, |
331 | .next_packet_pointer = 34, |
332 | .jump_bw = JMP_FW, |
333 | .jump_rel = JMP_ABS, |
334 | .operation = EQT, |
335 | .next_node = RSS_IPV4_TCP_NODE, |
336 | .next_branch = 4, |
337 | .data = 0x0, |
338 | .mask = 0xffff |
339 | }, |
340 | { |
341 | /* TCP SRC Port */ |
342 | .valid = 0, |
343 | .next_packet_pointer = 36, |
344 | .jump_bw = JMP_FW, |
345 | .jump_rel = JMP_ABS, |
346 | .operation = EQT, |
347 | .next_node = RSS_IPV4_TCP_NODE, |
348 | .next_branch = 5, |
349 | .data = 0x0, |
350 | .mask = 0xffff |
351 | }, |
352 | { |
353 | /* TCP DST Port */ |
354 | .valid = 0, |
355 | .next_packet_pointer = 256, |
356 | .jump_bw = JMP_FW, |
357 | .jump_rel = JMP_ABS, |
358 | .operation = EQT, |
359 | .next_node = LAST_NODE, |
360 | .next_branch = 0, |
361 | .data = 0x0, |
362 | .mask = 0xffff |
363 | } |
364 | } |
365 | }, |
366 | { |
367 | /* RSS_IPV4_UDP_NODE */ |
368 | .node_type = EWDN, |
369 | .last_node = 0, |
370 | .hdr_len_store = 1, |
371 | .hdr_extn = NO_BYTE, |
372 | .byte_store = NO_BYTE, |
373 | .search_byte_store = BOTH_BYTES, |
374 | .result_pointer = DB_RES_DROP, |
375 | .num_branches = 6, |
376 | .branch = { |
377 | { |
378 | /* SRC IPV4 B01 */ |
379 | .valid = 0, |
380 | .next_packet_pointer = 28, |
381 | .jump_bw = JMP_FW, |
382 | .jump_rel = JMP_ABS, |
383 | .operation = EQT, |
384 | .next_node = RSS_IPV4_UDP_NODE, |
385 | .next_branch = 1, |
386 | .data = 0x0, |
387 | .mask = 0xffff |
388 | }, |
389 | { |
390 | /* SRC IPV4 B23 */ |
391 | .valid = 0, |
392 | .next_packet_pointer = 30, |
393 | .jump_bw = JMP_FW, |
394 | .jump_rel = JMP_ABS, |
395 | .operation = EQT, |
396 | .next_node = RSS_IPV4_UDP_NODE, |
397 | .next_branch = 2, |
398 | .data = 0x0, |
399 | .mask = 0xffff |
400 | }, |
401 | { |
402 | /* DST IPV4 B01 */ |
403 | .valid = 0, |
404 | .next_packet_pointer = 32, |
405 | .jump_bw = JMP_FW, |
406 | .jump_rel = JMP_ABS, |
407 | .operation = EQT, |
408 | .next_node = RSS_IPV4_UDP_NODE, |
409 | .next_branch = 3, |
410 | .data = 0x0, |
411 | .mask = 0xffff |
412 | }, |
413 | { |
414 | /* DST IPV4 B23 */ |
415 | .valid = 0, |
416 | .next_packet_pointer = 34, |
417 | .jump_bw = JMP_FW, |
418 | .jump_rel = JMP_ABS, |
419 | .operation = EQT, |
420 | .next_node = RSS_IPV4_UDP_NODE, |
421 | .next_branch = 4, |
422 | .data = 0x0, |
423 | .mask = 0xffff |
424 | }, |
425 | { |
426 | /* TCP SRC Port */ |
427 | .valid = 0, |
428 | .next_packet_pointer = 36, |
429 | .jump_bw = JMP_FW, |
430 | .jump_rel = JMP_ABS, |
431 | .operation = EQT, |
432 | .next_node = RSS_IPV4_UDP_NODE, |
433 | .next_branch = 5, |
434 | .data = 0x0, |
435 | .mask = 0xffff |
436 | }, |
437 | { |
438 | /* TCP DST Port */ |
439 | .valid = 0, |
440 | .next_packet_pointer = 258, |
441 | .jump_bw = JMP_FW, |
442 | .jump_rel = JMP_ABS, |
443 | .operation = EQT, |
444 | .next_node = LAST_NODE, |
445 | .next_branch = 0, |
446 | .data = 0x0, |
447 | .mask = 0xffff |
448 | } |
449 | } |
450 | }, |
451 | { |
452 | /* RSS_IPV4_OTHERS_NODE */ |
453 | .node_type = EWDN, |
454 | .last_node = 0, |
455 | .hdr_len_store = 1, |
456 | .hdr_extn = NO_BYTE, |
457 | .byte_store = NO_BYTE, |
458 | .search_byte_store = BOTH_BYTES, |
459 | .result_pointer = DB_RES_DROP, |
460 | .num_branches = 6, |
461 | .branch = { |
462 | { |
463 | /* SRC IPV4 B01 */ |
464 | .valid = 0, |
465 | .next_packet_pointer = 28, |
466 | .jump_bw = JMP_FW, |
467 | .jump_rel = JMP_ABS, |
468 | .operation = EQT, |
469 | .next_node = RSS_IPV4_OTHERS_NODE, |
470 | .next_branch = 1, |
471 | .data = 0x0, |
472 | .mask = 0xffff |
473 | }, |
474 | { |
475 | /* SRC IPV4 B23 */ |
476 | .valid = 0, |
477 | .next_packet_pointer = 30, |
478 | .jump_bw = JMP_FW, |
479 | .jump_rel = JMP_ABS, |
480 | .operation = EQT, |
481 | .next_node = RSS_IPV4_OTHERS_NODE, |
482 | .next_branch = 2, |
483 | .data = 0x0, |
484 | .mask = 0xffff |
485 | }, |
486 | { |
487 | /* DST IPV4 B01 */ |
488 | .valid = 0, |
489 | .next_packet_pointer = 32, |
490 | .jump_bw = JMP_FW, |
491 | .jump_rel = JMP_ABS, |
492 | .operation = EQT, |
493 | .next_node = RSS_IPV4_OTHERS_NODE, |
494 | .next_branch = 3, |
495 | .data = 0x0, |
496 | .mask = 0xffff |
497 | }, |
498 | { |
499 | /* DST IPV4 B23 */ |
500 | .valid = 0, |
501 | .next_packet_pointer = 34, |
502 | .jump_bw = JMP_FW, |
503 | .jump_rel = JMP_ABS, |
504 | .operation = EQT, |
505 | .next_node = RSS_IPV4_OTHERS_NODE, |
506 | .next_branch = 4, |
507 | .data = 0x0, |
508 | .mask = 0xffff |
509 | }, |
510 | { |
511 | /* TCP SRC Port */ |
512 | .valid = 0, |
513 | .next_packet_pointer = 36, |
514 | .jump_bw = JMP_FW, |
515 | .jump_rel = JMP_ABS, |
516 | .operation = EQT, |
517 | .next_node = RSS_IPV4_OTHERS_NODE, |
518 | .next_branch = 5, |
519 | .data = 0x0, |
520 | .mask = 0xffff |
521 | }, |
522 | { |
523 | /* TCP DST Port */ |
524 | .valid = 0, |
525 | .next_packet_pointer = 260, |
526 | .jump_bw = JMP_FW, |
527 | .jump_rel = JMP_ABS, |
528 | .operation = EQT, |
529 | .next_node = LAST_NODE, |
530 | .next_branch = 0, |
531 | .data = 0x0, |
532 | .mask = 0xffff |
533 | } |
534 | } |
535 | }, |
536 | |
537 | { |
538 | /* LAST NODE */ |
539 | .node_type = EWDN, |
540 | .last_node = 1, |
541 | .hdr_len_store = 1, |
542 | .hdr_extn = NO_BYTE, |
543 | .byte_store = NO_BYTE, |
544 | .search_byte_store = NO_BYTE, |
545 | .result_pointer = DB_RES_DROP, |
546 | .num_branches = 1, |
547 | .branch = { |
548 | { |
549 | .valid = 0, |
550 | .next_packet_pointer = 0, |
551 | .jump_bw = JMP_FW, |
552 | .jump_rel = JMP_ABS, |
553 | .operation = EQT, |
554 | .next_node = MAX_NODES, |
555 | .next_branch = 0, |
556 | .data = 0, |
557 | .mask = 0xffff |
558 | } |
559 | } |
560 | } |
561 | }; |
562 | |
563 | static int xgene_cle_setup_node(struct xgene_enet_pdata *pdata, |
564 | struct xgene_enet_cle *cle) |
565 | { |
566 | struct xgene_cle_ptree *ptree = &cle->ptree; |
567 | const struct xgene_cle_ptree_ewdn *dn = xgene_init_ptree_dn; |
568 | int num_dn = ARRAY_SIZE(xgene_init_ptree_dn); |
569 | struct xgene_cle_ptree_kn *kn = ptree->kn; |
570 | u32 buf[CLE_DRAM_REGS]; |
571 | int i, j, ret; |
572 | |
573 | memset(buf, 0, sizeof(buf)); |
574 | for (i = 0; i < num_dn; i++) { |
575 | xgene_cle_dn_to_hw(dn: &dn[i], buf, jb: cle->jump_bytes); |
576 | ret = xgene_cle_dram_wr(cle, data: buf, nregs: 17, index: i + ptree->start_node, |
577 | type: PTREE_RAM, cmd: CLE_CMD_WR); |
578 | if (ret) |
579 | return ret; |
580 | } |
581 | |
582 | /* continue node index for key node */ |
583 | memset(buf, 0, sizeof(buf)); |
584 | for (j = i; j < (ptree->num_kn + num_dn); j++) { |
585 | xgene_cle_kn_to_hw(kn: &kn[j - num_dn], buf); |
586 | ret = xgene_cle_dram_wr(cle, data: buf, nregs: 17, index: j + ptree->start_node, |
587 | type: PTREE_RAM, cmd: CLE_CMD_WR); |
588 | if (ret) |
589 | return ret; |
590 | } |
591 | |
592 | return 0; |
593 | } |
594 | |
595 | static int xgene_cle_setup_ptree(struct xgene_enet_pdata *pdata, |
596 | struct xgene_enet_cle *cle) |
597 | { |
598 | int ret; |
599 | |
600 | ret = xgene_cle_setup_node(pdata, cle); |
601 | if (ret) |
602 | return ret; |
603 | |
604 | ret = xgene_cle_setup_dbptr(pdata, cle); |
605 | if (ret) |
606 | return ret; |
607 | |
608 | xgene_cle_enable_ptree(pdata, cle); |
609 | |
610 | return 0; |
611 | } |
612 | |
613 | static void xgene_cle_setup_def_dbptr(struct xgene_enet_pdata *pdata, |
614 | struct xgene_enet_cle *enet_cle, |
615 | struct xgene_cle_dbptr *dbptr, |
616 | u32 index, u8 priority) |
617 | { |
618 | void __iomem *base = enet_cle->base; |
619 | void __iomem *base_addr; |
620 | u32 buf[CLE_DRAM_REGS]; |
621 | u32 def_cls, offset; |
622 | u32 i, j; |
623 | |
624 | memset(buf, 0, sizeof(buf)); |
625 | xgene_cle_dbptr_to_hw(pdata, dbptr, buf); |
626 | |
627 | for (i = 0; i < enet_cle->parsers; i++) { |
628 | if (enet_cle->active_parser != PARSER_ALL) { |
629 | offset = enet_cle->active_parser * |
630 | CLE_PORT_OFFSET; |
631 | } else { |
632 | offset = i * CLE_PORT_OFFSET; |
633 | } |
634 | |
635 | base_addr = base + DFCLSRESDB00 + offset; |
636 | for (j = 0; j < 6; j++) |
637 | iowrite32(buf[j], base_addr + (j * 4)); |
638 | |
639 | def_cls = ((priority & 0x7) << 10) | (index & 0x3ff); |
640 | iowrite32(def_cls, base + DFCLSRESDBPTR0 + offset); |
641 | } |
642 | } |
643 | |
644 | static int xgene_cle_set_rss_sband(struct xgene_enet_cle *cle) |
645 | { |
646 | u32 idx = CLE_PKTRAM_SIZE / sizeof(u32); |
647 | u32 mac_hdr_len = ETH_HLEN; |
648 | u32 sband, reg = 0; |
649 | u32 ipv4_ihl = 5; |
650 | u32 hdr_len; |
651 | int ret; |
652 | |
653 | /* Sideband: IPV4/TCP packets */ |
654 | hdr_len = (mac_hdr_len << 5) | ipv4_ihl; |
655 | xgene_cle_sband_to_hw(frag: 0, ver: XGENE_CLE_IPV4, type: XGENE_CLE_TCP, len: hdr_len, reg: ®); |
656 | sband = reg; |
657 | |
658 | /* Sideband: IPv4/UDP packets */ |
659 | hdr_len = (mac_hdr_len << 5) | ipv4_ihl; |
660 | xgene_cle_sband_to_hw(frag: 1, ver: XGENE_CLE_IPV4, type: XGENE_CLE_UDP, len: hdr_len, reg: ®); |
661 | sband |= (reg << 16); |
662 | |
663 | ret = xgene_cle_dram_wr(cle, data: &sband, nregs: 1, index: idx, type: PKT_RAM, cmd: CLE_CMD_WR); |
664 | if (ret) |
665 | return ret; |
666 | |
667 | /* Sideband: IPv4/RAW packets */ |
668 | hdr_len = (mac_hdr_len << 5) | ipv4_ihl; |
669 | xgene_cle_sband_to_hw(frag: 0, ver: XGENE_CLE_IPV4, type: XGENE_CLE_OTHER, |
670 | len: hdr_len, reg: ®); |
671 | sband = reg; |
672 | |
673 | /* Sideband: Ethernet II/RAW packets */ |
674 | hdr_len = (mac_hdr_len << 5); |
675 | xgene_cle_sband_to_hw(frag: 0, ver: XGENE_CLE_IPV4, type: XGENE_CLE_OTHER, |
676 | len: hdr_len, reg: ®); |
677 | sband |= (reg << 16); |
678 | |
679 | ret = xgene_cle_dram_wr(cle, data: &sband, nregs: 1, index: idx + 1, type: PKT_RAM, cmd: CLE_CMD_WR); |
680 | if (ret) |
681 | return ret; |
682 | |
683 | return 0; |
684 | } |
685 | |
686 | static int (struct xgene_enet_cle *cle) |
687 | { |
688 | u32 secret_key_ipv4[4]; /* 16 Bytes*/ |
689 | int ret = 0; |
690 | |
691 | get_random_bytes(buf: secret_key_ipv4, len: 16); |
692 | ret = xgene_cle_dram_wr(cle, data: secret_key_ipv4, nregs: 4, index: 0, |
693 | type: RSS_IPV4_HASH_SKEY, cmd: CLE_CMD_WR); |
694 | return ret; |
695 | } |
696 | |
697 | static int (struct xgene_enet_pdata *pdata) |
698 | { |
699 | u32 fpsel, dstqid, nfpsel, idt_reg, idx; |
700 | int i, ret = 0; |
701 | u16 pool_id; |
702 | |
703 | for (i = 0; i < XGENE_CLE_IDT_ENTRIES; i++) { |
704 | idx = i % pdata->rxq_cnt; |
705 | pool_id = pdata->rx_ring[idx]->buf_pool->id; |
706 | fpsel = xgene_enet_get_fpsel(id: pool_id); |
707 | dstqid = xgene_enet_dst_ring_num(ring: pdata->rx_ring[idx]); |
708 | nfpsel = 0; |
709 | if (pdata->rx_ring[idx]->page_pool) { |
710 | pool_id = pdata->rx_ring[idx]->page_pool->id; |
711 | nfpsel = xgene_enet_get_fpsel(id: pool_id); |
712 | } |
713 | |
714 | idt_reg = 0; |
715 | xgene_cle_idt_to_hw(pdata, dstqid, fpsel, nfpsel, idt_reg: &idt_reg); |
716 | ret = xgene_cle_dram_wr(cle: &pdata->cle, data: &idt_reg, nregs: 1, index: i, |
717 | type: RSS_IDT, cmd: CLE_CMD_WR); |
718 | if (ret) |
719 | return ret; |
720 | } |
721 | |
722 | ret = xgene_cle_set_rss_skeys(cle: &pdata->cle); |
723 | if (ret) |
724 | return ret; |
725 | |
726 | return 0; |
727 | } |
728 | |
729 | static int (struct xgene_enet_pdata *pdata) |
730 | { |
731 | struct xgene_enet_cle *cle = &pdata->cle; |
732 | void __iomem *base = cle->base; |
733 | u32 offset, val = 0; |
734 | int i, ret = 0; |
735 | |
736 | offset = CLE_PORT_OFFSET; |
737 | for (i = 0; i < cle->parsers; i++) { |
738 | if (cle->active_parser != PARSER_ALL) |
739 | offset = cle->active_parser * CLE_PORT_OFFSET; |
740 | else |
741 | offset = i * CLE_PORT_OFFSET; |
742 | |
743 | /* enable RSS */ |
744 | val = (RSS_IPV4_12B << 1) | 0x1; |
745 | writel(val, addr: base + RSS_CTRL0 + offset); |
746 | } |
747 | |
748 | /* setup sideband data */ |
749 | ret = xgene_cle_set_rss_sband(cle); |
750 | if (ret) |
751 | return ret; |
752 | |
753 | /* setup indirection table */ |
754 | ret = xgene_cle_set_rss_idt(pdata); |
755 | if (ret) |
756 | return ret; |
757 | |
758 | return 0; |
759 | } |
760 | |
761 | static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata) |
762 | { |
763 | struct xgene_enet_cle *enet_cle = &pdata->cle; |
764 | u32 def_qid, def_fpsel, def_nxtfpsel, pool_id; |
765 | struct xgene_cle_dbptr dbptr[DB_MAX_PTRS]; |
766 | struct xgene_cle_ptree *ptree; |
767 | struct xgene_cle_ptree_kn kn; |
768 | int ret; |
769 | |
770 | if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) |
771 | return -EINVAL; |
772 | |
773 | ptree = &enet_cle->ptree; |
774 | ptree->start_pkt = 12; /* Ethertype */ |
775 | |
776 | ret = xgene_cle_setup_rss(pdata); |
777 | if (ret) { |
778 | netdev_err(dev: pdata->ndev, format: "RSS initialization failed\n" ); |
779 | return ret; |
780 | } |
781 | |
782 | def_qid = xgene_enet_dst_ring_num(ring: pdata->rx_ring[0]); |
783 | pool_id = pdata->rx_ring[0]->buf_pool->id; |
784 | def_fpsel = xgene_enet_get_fpsel(id: pool_id); |
785 | def_nxtfpsel = 0; |
786 | if (pdata->rx_ring[0]->page_pool) { |
787 | pool_id = pdata->rx_ring[0]->page_pool->id; |
788 | def_nxtfpsel = xgene_enet_get_fpsel(id: pool_id); |
789 | } |
790 | |
791 | memset(dbptr, 0, sizeof(struct xgene_cle_dbptr) * DB_MAX_PTRS); |
792 | dbptr[DB_RES_ACCEPT].fpsel = def_fpsel; |
793 | dbptr[DB_RES_ACCEPT].nxtfpsel = def_nxtfpsel; |
794 | dbptr[DB_RES_ACCEPT].dstqid = def_qid; |
795 | dbptr[DB_RES_ACCEPT].cle_priority = 1; |
796 | |
797 | dbptr[DB_RES_DEF].fpsel = def_fpsel; |
798 | dbptr[DB_RES_DEF].nxtfpsel = def_nxtfpsel; |
799 | dbptr[DB_RES_DEF].dstqid = def_qid; |
800 | dbptr[DB_RES_DEF].cle_priority = 7; |
801 | xgene_cle_setup_def_dbptr(pdata, enet_cle, dbptr: &dbptr[DB_RES_DEF], |
802 | index: DB_RES_ACCEPT, priority: 7); |
803 | |
804 | dbptr[DB_RES_DROP].drop = 1; |
805 | |
806 | memset(&kn, 0, sizeof(kn)); |
807 | kn.node_type = KN; |
808 | kn.num_keys = 1; |
809 | kn.key[0].priority = 0; |
810 | kn.key[0].result_pointer = DB_RES_ACCEPT; |
811 | |
812 | ptree->kn = &kn; |
813 | ptree->dbptr = dbptr; |
814 | ptree->num_kn = 1; |
815 | ptree->num_dbptr = DB_MAX_PTRS; |
816 | |
817 | return xgene_cle_setup_ptree(pdata, cle: enet_cle); |
818 | } |
819 | |
820 | const struct xgene_cle_ops xgene_cle3in_ops = { |
821 | .cle_init = xgene_enet_cle_init, |
822 | }; |
823 | |