net: lan966x: Add IS1 VCAP keyset configuration for lan966x
[linux-block.git] / drivers / net / ethernet / microchip / lan966x / lan966x_vcap_impl.c
CommitLineData
b0531225
HV
1// SPDX-License-Identifier: GPL-2.0+
2
3#include "lan966x_main.h"
39bedc16 4#include "lan966x_vcap_ag_api.h"
b0531225 5#include "vcap_api.h"
3643abd6 6#include "vcap_api_client.h"
94281484 7#include "vcap_api_debugfs.h"
3643abd6 8
3643abd6
HV
9#define STREAMSIZE (64 * 4)
10
a4d9b3ec 11#define LAN966X_IS1_LOOKUPS 3
3643abd6
HV
12#define LAN966X_IS2_LOOKUPS 2
13
14static struct lan966x_vcap_inst {
15 enum vcap_type vtype; /* type of vcap */
16 int tgt_inst; /* hardware instance number */
17 int lookups; /* number of lookups in this vcap type */
18 int first_cid; /* first chain id in this vcap */
19 int last_cid; /* last chain id in this vcap */
20 int count; /* number of available addresses */
e7e3f514 21 bool ingress; /* is vcap in the ingress path */
3643abd6 22} lan966x_vcap_inst_cfg[] = {
a4d9b3ec
HV
23 {
24 .vtype = VCAP_TYPE_IS1, /* IS1-0 */
25 .tgt_inst = 1,
26 .lookups = LAN966X_IS1_LOOKUPS,
27 .first_cid = LAN966X_VCAP_CID_IS1_L0,
28 .last_cid = LAN966X_VCAP_CID_IS1_MAX,
29 .count = 768,
30 .ingress = true,
31 },
3643abd6
HV
32 {
33 .vtype = VCAP_TYPE_IS2, /* IS2-0 */
34 .tgt_inst = 2,
35 .lookups = LAN966X_IS2_LOOKUPS,
36 .first_cid = LAN966X_VCAP_CID_IS2_L0,
37 .last_cid = LAN966X_VCAP_CID_IS2_MAX,
38 .count = 256,
e7e3f514 39 .ingress = true,
3643abd6
HV
40 },
41};
42
43struct lan966x_vcap_cmd_cb {
44 struct lan966x *lan966x;
45 u32 instance;
46};
47
48static u32 lan966x_vcap_read_update_ctrl(const struct lan966x_vcap_cmd_cb *cb)
49{
50 return lan_rd(cb->lan966x, VCAP_UPDATE_CTRL(cb->instance));
51}
52
53static void lan966x_vcap_wait_update(struct lan966x *lan966x, int instance)
54{
55 const struct lan966x_vcap_cmd_cb cb = { .lan966x = lan966x,
56 .instance = instance };
57 u32 val;
58
59 readx_poll_timeout(lan966x_vcap_read_update_ctrl, &cb, val,
60 (val & VCAP_UPDATE_CTRL_UPDATE_SHOT) == 0, 10,
61 100000);
62}
63
64static void __lan966x_vcap_range_init(struct lan966x *lan966x,
65 struct vcap_admin *admin,
66 u32 addr,
67 u32 count)
68{
69 lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
70 VCAP_MV_CFG_MV_SIZE_SET(count - 1),
71 lan966x, VCAP_MV_CFG(admin->tgt_inst));
72
73 lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |
74 VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
75 VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
76 VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
77 VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
78 VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(true) |
79 VCAP_UPDATE_CTRL_UPDATE_SHOT_SET(1),
80 lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
81
82 lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
83}
84
a4d9b3ec
HV
85static int lan966x_vcap_is1_cid_to_lookup(int cid)
86{
87 int lookup = 0;
88
89 if (cid >= LAN966X_VCAP_CID_IS1_L1 &&
90 cid < LAN966X_VCAP_CID_IS1_L2)
91 lookup = 1;
92 else if (cid >= LAN966X_VCAP_CID_IS1_L2 &&
93 cid < LAN966X_VCAP_CID_IS1_MAX)
94 lookup = 2;
95
96 return lookup;
97}
98
99static int lan966x_vcap_is2_cid_to_lookup(int cid)
4426b78c
HV
100{
101 if (cid >= LAN966X_VCAP_CID_IS2_L1 &&
102 cid < LAN966X_VCAP_CID_IS2_MAX)
103 return 1;
104
105 return 0;
106}
107
a4d9b3ec
HV
108/* Return the list of keysets for the vcap port configuration */
109static int
110lan966x_vcap_is1_get_port_keysets(struct net_device *ndev, int lookup,
111 struct vcap_keyset_list *keysetlist,
112 u16 l3_proto)
113{
114 struct lan966x_port *port = netdev_priv(ndev);
115 struct lan966x *lan966x = port->lan966x;
116 u32 val;
117
118 val = lan_rd(lan966x, ANA_VCAP_S1_CFG(port->chip_port, lookup));
119
120 /* Collect all keysets for the port in a list */
121 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
122 switch (ANA_VCAP_S1_CFG_KEY_IP4_CFG_GET(val)) {
123 case VCAP_IS1_PS_IPV4_7TUPLE:
124 vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
125 break;
126 case VCAP_IS1_PS_IPV4_5TUPLE_IP4:
127 vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);
128 break;
129 case VCAP_IS1_PS_IPV4_NORMAL:
130 vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
131 break;
132 }
133 }
134
135 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
136 switch (ANA_VCAP_S1_CFG_KEY_IP6_CFG_GET(val)) {
137 case VCAP_IS1_PS_IPV6_NORMAL:
138 case VCAP_IS1_PS_IPV6_NORMAL_IP6:
139 vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
140 vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL_IP6);
141 break;
142 case VCAP_IS1_PS_IPV6_5TUPLE_IP6:
143 vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP6);
144 break;
145 case VCAP_IS1_PS_IPV6_7TUPLE:
146 vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
147 break;
148 case VCAP_IS1_PS_IPV6_5TUPLE_IP4:
149 vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);
150 break;
151 case VCAP_IS1_PS_IPV6_DMAC_VID:
152 vcap_keyset_list_add(keysetlist, VCAP_KFS_DMAC_VID);
153 break;
154 }
155 }
156
157 switch (ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(val)) {
158 case VCAP_IS1_PS_OTHER_7TUPLE:
159 vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
160 break;
161 case VCAP_IS1_PS_OTHER_NORMAL:
162 vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
163 break;
164 }
165
166 return 0;
167}
168
4426b78c
HV
169static int
170lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup,
171 struct vcap_keyset_list *keysetlist,
172 u16 l3_proto)
173{
174 struct lan966x_port *port = netdev_priv(dev);
175 struct lan966x *lan966x = port->lan966x;
176 bool found = false;
177 u32 val;
178
4426b78c 179 val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port));
4426b78c
HV
180
181 /* Collect all keysets for the port in a list */
182 if (l3_proto == ETH_P_ALL)
183 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
184
185 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_SNAP) {
186 if (ANA_VCAP_S2_CFG_SNAP_DIS_GET(val) & (BIT(0) << lookup))
187 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_LLC);
188 else
189 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_SNAP);
190
191 found = true;
192 }
193
194 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_CFM) {
195 if (ANA_VCAP_S2_CFG_OAM_DIS_GET(val) & (BIT(0) << lookup))
196 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
197 else
198 vcap_keyset_list_add(keysetlist, VCAP_KFS_OAM);
199
200 found = true;
201 }
202
203 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {
204 if (ANA_VCAP_S2_CFG_ARP_DIS_GET(val) & (BIT(0) << lookup))
205 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
206 else
207 vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);
208
209 found = true;
210 }
211
212 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
213 if (ANA_VCAP_S2_CFG_IP_OTHER_DIS_GET(val) & (BIT(0) << lookup))
214 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
215 else
216 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
217
218 if (ANA_VCAP_S2_CFG_IP_TCPUDP_DIS_GET(val) & (BIT(0) << lookup))
219 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
220 else
221 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
222
223 found = true;
224 }
225
226 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
227 switch (ANA_VCAP_S2_CFG_IP6_CFG_GET(val) & (0x3 << lookup)) {
228 case VCAP_IS2_PS_IPV6_TCPUDP_OTHER:
229 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_OTHER);
230 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_TCP_UDP);
231 break;
232 case VCAP_IS2_PS_IPV6_STD:
233 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);
234 break;
235 case VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER:
236 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
237 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
238 break;
239 case VCAP_IS2_PS_IPV6_MAC_ETYPE:
240 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
241 break;
242 }
243
244 found = true;
245 }
246
247 if (!found)
248 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
249
250 return 0;
251}
252
253static enum vcap_keyfield_set
254lan966x_vcap_validate_keyset(struct net_device *dev,
255 struct vcap_admin *admin,
256 struct vcap_rule *rule,
257 struct vcap_keyset_list *kslist,
258 u16 l3_proto)
259{
260 struct vcap_keyset_list keysetlist = {};
261 enum vcap_keyfield_set keysets[10] = {};
262 int lookup;
263 int err;
264
265 if (!kslist || kslist->cnt == 0)
266 return VCAP_KFS_NO_VALUE;
267
4426b78c
HV
268 keysetlist.max = ARRAY_SIZE(keysets);
269 keysetlist.keysets = keysets;
a4d9b3ec
HV
270
271 switch (admin->vtype) {
272 case VCAP_TYPE_IS1:
273 lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);
274 err = lan966x_vcap_is1_get_port_keysets(dev, lookup, &keysetlist,
275 l3_proto);
276 break;
277 case VCAP_TYPE_IS2:
278 lookup = lan966x_vcap_is2_cid_to_lookup(rule->vcap_chain_id);
279 err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist,
280 l3_proto);
281 break;
282 default:
283 pr_err("vcap type: %s not supported\n",
284 lan966x_vcaps[admin->vtype].name);
285 return VCAP_KFS_NO_VALUE;
286 }
287
4426b78c
HV
288 if (err)
289 return VCAP_KFS_NO_VALUE;
290
291 /* Check if there is a match and return the match */
292 for (int i = 0; i < kslist->cnt; ++i)
293 for (int j = 0; j < keysetlist.cnt; ++j)
294 if (kslist->keysets[i] == keysets[j])
295 return kslist->keysets[i];
296
297 return VCAP_KFS_NO_VALUE;
298}
299
a4d9b3ec 300static bool lan966x_vcap_is2_is_first_chain(struct vcap_rule *rule)
4426b78c
HV
301{
302 return (rule->vcap_chain_id >= LAN966X_VCAP_CID_IS2_L0 &&
303 rule->vcap_chain_id < LAN966X_VCAP_CID_IS2_L1);
304}
305
a4d9b3ec
HV
306static void lan966x_vcap_is1_add_default_fields(struct lan966x_port *port,
307 struct vcap_admin *admin,
308 struct vcap_rule *rule)
309{
310 u32 value, mask;
311 u32 lookup;
312
313 if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
314 &value, &mask))
315 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
316 ~BIT(port->chip_port));
317
318 lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);
319 vcap_rule_add_key_u32(rule, VCAP_KF_LOOKUP_INDEX, lookup, 0x3);
320}
321
322static void lan966x_vcap_is2_add_default_fields(struct lan966x_port *port,
323 struct vcap_admin *admin,
324 struct vcap_rule *rule)
4426b78c 325{
72df3489 326 u32 value, mask;
4426b78c 327
72df3489
HV
328 if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
329 &value, &mask))
330 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
331 ~BIT(port->chip_port));
4426b78c 332
a4d9b3ec 333 if (lan966x_vcap_is2_is_first_chain(rule))
4426b78c
HV
334 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
335 VCAP_BIT_1);
336 else
337 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
338 VCAP_BIT_0);
339}
340
a4d9b3ec
HV
341static void lan966x_vcap_add_default_fields(struct net_device *dev,
342 struct vcap_admin *admin,
343 struct vcap_rule *rule)
344{
345 struct lan966x_port *port = netdev_priv(dev);
346
347 switch (admin->vtype) {
348 case VCAP_TYPE_IS1:
349 lan966x_vcap_is1_add_default_fields(port, admin, rule);
350 break;
351 case VCAP_TYPE_IS2:
352 lan966x_vcap_is2_add_default_fields(port, admin, rule);
353 break;
354 default:
355 pr_err("vcap type: %s not supported\n",
356 lan966x_vcaps[admin->vtype].name);
357 break;
358 }
359}
360
4426b78c
HV
361static void lan966x_vcap_cache_erase(struct vcap_admin *admin)
362{
363 memset(admin->cache.keystream, 0, STREAMSIZE);
364 memset(admin->cache.maskstream, 0, STREAMSIZE);
365 memset(admin->cache.actionstream, 0, STREAMSIZE);
366 memset(&admin->cache.counter, 0, sizeof(admin->cache.counter));
367}
368
369static void lan966x_vcap_cache_write(struct net_device *dev,
370 struct vcap_admin *admin,
371 enum vcap_selection sel,
372 u32 start,
373 u32 count)
374{
375 struct lan966x_port *port = netdev_priv(dev);
376 struct lan966x *lan966x = port->lan966x;
377 u32 *keystr, *mskstr, *actstr;
378
379 keystr = &admin->cache.keystream[start];
380 mskstr = &admin->cache.maskstream[start];
381 actstr = &admin->cache.actionstream[start];
382
383 switch (sel) {
384 case VCAP_SEL_ENTRY:
385 for (int i = 0; i < count; ++i) {
386 lan_wr(keystr[i] & mskstr[i], lan966x,
387 VCAP_ENTRY_DAT(admin->tgt_inst, i));
388 lan_wr(~mskstr[i], lan966x,
389 VCAP_MASK_DAT(admin->tgt_inst, i));
390 }
391 break;
392 case VCAP_SEL_ACTION:
393 for (int i = 0; i < count; ++i)
394 lan_wr(actstr[i], lan966x,
395 VCAP_ACTION_DAT(admin->tgt_inst, i));
396 break;
397 case VCAP_SEL_COUNTER:
398 admin->cache.sticky = admin->cache.counter > 0;
399 lan_wr(admin->cache.counter, lan966x,
400 VCAP_CNT_DAT(admin->tgt_inst, 0));
401 break;
402 default:
403 break;
404 }
405}
406
407static void lan966x_vcap_cache_read(struct net_device *dev,
408 struct vcap_admin *admin,
409 enum vcap_selection sel,
410 u32 start,
411 u32 count)
412{
413 struct lan966x_port *port = netdev_priv(dev);
414 struct lan966x *lan966x = port->lan966x;
415 int instance = admin->tgt_inst;
416 u32 *keystr, *mskstr, *actstr;
417
418 keystr = &admin->cache.keystream[start];
419 mskstr = &admin->cache.maskstream[start];
420 actstr = &admin->cache.actionstream[start];
421
422 if (sel & VCAP_SEL_ENTRY) {
423 for (int i = 0; i < count; ++i) {
424 keystr[i] =
425 lan_rd(lan966x, VCAP_ENTRY_DAT(instance, i));
426 mskstr[i] =
427 ~lan_rd(lan966x, VCAP_MASK_DAT(instance, i));
428 }
429 }
430
431 if (sel & VCAP_SEL_ACTION)
432 for (int i = 0; i < count; ++i)
433 actstr[i] =
434 lan_rd(lan966x, VCAP_ACTION_DAT(instance, i));
435
436 if (sel & VCAP_SEL_COUNTER) {
437 admin->cache.counter =
438 lan_rd(lan966x, VCAP_CNT_DAT(instance, 0));
439 admin->cache.sticky = admin->cache.counter > 0;
440 }
441}
442
443static void lan966x_vcap_range_init(struct net_device *dev,
444 struct vcap_admin *admin,
445 u32 addr,
446 u32 count)
447{
448 struct lan966x_port *port = netdev_priv(dev);
449 struct lan966x *lan966x = port->lan966x;
450
451 __lan966x_vcap_range_init(lan966x, admin, addr, count);
452}
453
454static void lan966x_vcap_update(struct net_device *dev,
455 struct vcap_admin *admin,
456 enum vcap_command cmd,
457 enum vcap_selection sel,
458 u32 addr)
459{
460 struct lan966x_port *port = netdev_priv(dev);
461 struct lan966x *lan966x = port->lan966x;
462 bool clear;
463
464 clear = (cmd == VCAP_CMD_INITIALIZE);
465
466 lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
467 VCAP_MV_CFG_MV_SIZE_SET(0),
468 lan966x, VCAP_MV_CFG(admin->tgt_inst));
469
470 lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
471 VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |
472 VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |
473 VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |
474 VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
475 VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(clear) |
476 VCAP_UPDATE_CTRL_UPDATE_SHOT,
477 lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
478
479 lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
480}
481
482static void lan966x_vcap_move(struct net_device *dev,
483 struct vcap_admin *admin,
484 u32 addr, int offset, int count)
485{
486 struct lan966x_port *port = netdev_priv(dev);
487 struct lan966x *lan966x = port->lan966x;
488 enum vcap_command cmd;
489 u16 mv_num_pos;
490 u16 mv_size;
491
492 mv_size = count - 1;
493 if (offset > 0) {
494 mv_num_pos = offset - 1;
495 cmd = VCAP_CMD_MOVE_DOWN;
496 } else {
497 mv_num_pos = -offset - 1;
498 cmd = VCAP_CMD_MOVE_UP;
499 }
500
501 lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(mv_num_pos) |
502 VCAP_MV_CFG_MV_SIZE_SET(mv_size),
503 lan966x, VCAP_MV_CFG(admin->tgt_inst));
504
505 lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
506 VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
507 VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
508 VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
509 VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
510 VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(false) |
511 VCAP_UPDATE_CTRL_UPDATE_SHOT,
512 lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
513
514 lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
515}
516
4426b78c
HV
517static struct vcap_operations lan966x_vcap_ops = {
518 .validate_keyset = lan966x_vcap_validate_keyset,
519 .add_default_fields = lan966x_vcap_add_default_fields,
520 .cache_erase = lan966x_vcap_cache_erase,
521 .cache_write = lan966x_vcap_cache_write,
522 .cache_read = lan966x_vcap_cache_read,
523 .init = lan966x_vcap_range_init,
524 .update = lan966x_vcap_update,
525 .move = lan966x_vcap_move,
526 .port_info = lan966x_vcap_port_info,
4426b78c
HV
527};
528
3643abd6
HV
529static void lan966x_vcap_admin_free(struct vcap_admin *admin)
530{
531 if (!admin)
532 return;
533
534 kfree(admin->cache.keystream);
535 kfree(admin->cache.maskstream);
536 kfree(admin->cache.actionstream);
537 mutex_destroy(&admin->lock);
538 kfree(admin);
539}
540
541static struct vcap_admin *
542lan966x_vcap_admin_alloc(struct lan966x *lan966x, struct vcap_control *ctrl,
543 const struct lan966x_vcap_inst *cfg)
544{
545 struct vcap_admin *admin;
546
547 admin = kzalloc(sizeof(*admin), GFP_KERNEL);
548 if (!admin)
549 return ERR_PTR(-ENOMEM);
550
551 mutex_init(&admin->lock);
552 INIT_LIST_HEAD(&admin->list);
553 INIT_LIST_HEAD(&admin->rules);
4426b78c
HV
554 INIT_LIST_HEAD(&admin->enabled);
555
3643abd6
HV
556 admin->vtype = cfg->vtype;
557 admin->vinst = 0;
e7e3f514 558 admin->ingress = cfg->ingress;
4426b78c
HV
559 admin->w32be = true;
560 admin->tgt_inst = cfg->tgt_inst;
561
3643abd6
HV
562 admin->lookups = cfg->lookups;
563 admin->lookups_per_instance = cfg->lookups;
4426b78c 564
3643abd6
HV
565 admin->first_cid = cfg->first_cid;
566 admin->last_cid = cfg->last_cid;
4426b78c 567
3643abd6
HV
568 admin->cache.keystream = kzalloc(STREAMSIZE, GFP_KERNEL);
569 admin->cache.maskstream = kzalloc(STREAMSIZE, GFP_KERNEL);
570 admin->cache.actionstream = kzalloc(STREAMSIZE, GFP_KERNEL);
571 if (!admin->cache.keystream ||
572 !admin->cache.maskstream ||
573 !admin->cache.actionstream) {
574 lan966x_vcap_admin_free(admin);
575 return ERR_PTR(-ENOMEM);
576 }
577
578 return admin;
579}
580
581static void lan966x_vcap_block_init(struct lan966x *lan966x,
582 struct vcap_admin *admin,
583 struct lan966x_vcap_inst *cfg)
584{
585 admin->first_valid_addr = 0;
586 admin->last_used_addr = cfg->count;
587 admin->last_valid_addr = cfg->count - 1;
588
589 lan_wr(VCAP_CORE_IDX_CORE_IDX_SET(0),
590 lan966x, VCAP_CORE_IDX(admin->tgt_inst));
591 lan_wr(VCAP_CORE_MAP_CORE_MAP_SET(1),
592 lan966x, VCAP_CORE_MAP(admin->tgt_inst));
593
594 __lan966x_vcap_range_init(lan966x, admin, admin->first_valid_addr,
595 admin->last_valid_addr -
596 admin->first_valid_addr);
597}
b0531225 598
4426b78c
HV
599static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x,
600 struct vcap_admin *admin)
601{
a4d9b3ec
HV
602 u32 val;
603
604 switch (admin->vtype) {
605 case VCAP_TYPE_IS1:
606 val = ANA_VCAP_S1_CFG_KEY_IP6_CFG_SET(VCAP_IS1_PS_IPV6_5TUPLE_IP6) |
607 ANA_VCAP_S1_CFG_KEY_IP4_CFG_SET(VCAP_IS1_PS_IPV4_5TUPLE_IP4) |
608 ANA_VCAP_S1_CFG_KEY_OTHER_CFG_SET(VCAP_IS1_PS_OTHER_NORMAL);
609
610 for (int p = 0; p < lan966x->num_phys_ports; ++p) {
611 if (!lan966x->ports[p])
612 continue;
613
614 for (int l = 0; l < LAN966X_IS1_LOOKUPS; ++l)
615 lan_wr(val, lan966x, ANA_VCAP_S1_CFG(p, l));
616
617 lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),
618 ANA_VCAP_CFG_S1_ENA, lan966x,
619 ANA_VCAP_CFG(p));
620 }
621
622 break;
623 case VCAP_TYPE_IS2:
624 for (int p = 0; p < lan966x->num_phys_ports; ++p)
625 lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p));
626
627 break;
628 default:
629 pr_err("vcap type: %s not supported\n",
630 lan966x_vcaps[admin->vtype].name);
631 break;
632 }
4426b78c
HV
633}
634
b0531225
HV
635int lan966x_vcap_init(struct lan966x *lan966x)
636{
3643abd6 637 struct lan966x_vcap_inst *cfg;
b0531225 638 struct vcap_control *ctrl;
3643abd6 639 struct vcap_admin *admin;
94281484 640 struct dentry *dir;
b0531225
HV
641
642 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
643 if (!ctrl)
644 return -ENOMEM;
645
39bedc16
HV
646 ctrl->vcaps = lan966x_vcaps;
647 ctrl->stats = &lan966x_vcap_stats;
4426b78c 648 ctrl->ops = &lan966x_vcap_ops;
39bedc16 649
3643abd6
HV
650 INIT_LIST_HEAD(&ctrl->list);
651 for (int i = 0; i < ARRAY_SIZE(lan966x_vcap_inst_cfg); ++i) {
652 cfg = &lan966x_vcap_inst_cfg[i];
653
654 admin = lan966x_vcap_admin_alloc(lan966x, ctrl, cfg);
655 if (IS_ERR(admin))
656 return PTR_ERR(admin);
657
658 lan966x_vcap_block_init(lan966x, admin, cfg);
4426b78c
HV
659 lan966x_vcap_port_key_deselection(lan966x, admin);
660
3643abd6
HV
661 list_add_tail(&admin->list, &ctrl->list);
662 }
663
94281484
HV
664 dir = vcap_debugfs(lan966x->dev, lan966x->debugfs_root, ctrl);
665 for (int p = 0; p < lan966x->num_phys_ports; ++p) {
666 if (lan966x->ports[p]) {
667 vcap_port_debugfs(lan966x->dev, dir, ctrl,
668 lan966x->ports[p]->dev);
669
01ef75a2
SH
670 lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(true),
671 ANA_VCAP_S2_CFG_ENA, lan966x,
672 ANA_VCAP_S2_CFG(lan966x->ports[p]->chip_port));
a4d9b3ec
HV
673
674 lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),
675 ANA_VCAP_CFG_S1_ENA, lan966x,
676 ANA_VCAP_CFG(lan966x->ports[p]->chip_port));
94281484
HV
677 }
678 }
01ef75a2 679
b0531225
HV
680 lan966x->vcap_ctrl = ctrl;
681
682 return 0;
683}
684
685void lan966x_vcap_deinit(struct lan966x *lan966x)
686{
3643abd6 687 struct vcap_admin *admin, *admin_next;
b0531225
HV
688 struct vcap_control *ctrl;
689
690 ctrl = lan966x->vcap_ctrl;
691 if (!ctrl)
692 return;
693
3643abd6 694 list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) {
4426b78c 695 lan966x_vcap_port_key_deselection(lan966x, admin);
3643abd6
HV
696 vcap_del_rules(ctrl, admin);
697 list_del(&admin->list);
698 lan966x_vcap_admin_free(admin);
699 }
700
b0531225
HV
701 kfree(ctrl);
702}