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

source code of linux/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c