Loading...
Note: File does not exist in v5.4.
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
8#define STREAMSIZE (64 * 4)
9
10#define LAN966X_IS2_LOOKUPS 2
11
12enum vcap_is2_port_sel_ipv6 {
13 VCAP_IS2_PS_IPV6_TCPUDP_OTHER,
14 VCAP_IS2_PS_IPV6_STD,
15 VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER,
16 VCAP_IS2_PS_IPV6_MAC_ETYPE,
17};
18
19static struct lan966x_vcap_inst {
20 enum vcap_type vtype; /* type of vcap */
21 int tgt_inst; /* hardware instance number */
22 int lookups; /* number of lookups in this vcap type */
23 int first_cid; /* first chain id in this vcap */
24 int last_cid; /* last chain id in this vcap */
25 int count; /* number of available addresses */
26} lan966x_vcap_inst_cfg[] = {
27 {
28 .vtype = VCAP_TYPE_IS2, /* IS2-0 */
29 .tgt_inst = 2,
30 .lookups = LAN966X_IS2_LOOKUPS,
31 .first_cid = LAN966X_VCAP_CID_IS2_L0,
32 .last_cid = LAN966X_VCAP_CID_IS2_MAX,
33 .count = 256,
34 },
35};
36
37struct lan966x_vcap_cmd_cb {
38 struct lan966x *lan966x;
39 u32 instance;
40};
41
42static u32 lan966x_vcap_read_update_ctrl(const struct lan966x_vcap_cmd_cb *cb)
43{
44 return lan_rd(cb->lan966x, VCAP_UPDATE_CTRL(cb->instance));
45}
46
47static void lan966x_vcap_wait_update(struct lan966x *lan966x, int instance)
48{
49 const struct lan966x_vcap_cmd_cb cb = { .lan966x = lan966x,
50 .instance = instance };
51 u32 val;
52
53 readx_poll_timeout(lan966x_vcap_read_update_ctrl, &cb, val,
54 (val & VCAP_UPDATE_CTRL_UPDATE_SHOT) == 0, 10,
55 100000);
56}
57
58static void __lan966x_vcap_range_init(struct lan966x *lan966x,
59 struct vcap_admin *admin,
60 u32 addr,
61 u32 count)
62{
63 lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
64 VCAP_MV_CFG_MV_SIZE_SET(count - 1),
65 lan966x, VCAP_MV_CFG(admin->tgt_inst));
66
67 lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |
68 VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
69 VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
70 VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
71 VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
72 VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(true) |
73 VCAP_UPDATE_CTRL_UPDATE_SHOT_SET(1),
74 lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
75
76 lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
77}
78
79static int lan966x_vcap_cid_to_lookup(int cid)
80{
81 if (cid >= LAN966X_VCAP_CID_IS2_L1 &&
82 cid < LAN966X_VCAP_CID_IS2_MAX)
83 return 1;
84
85 return 0;
86}
87
88static int
89lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup,
90 struct vcap_keyset_list *keysetlist,
91 u16 l3_proto)
92{
93 struct lan966x_port *port = netdev_priv(dev);
94 struct lan966x *lan966x = port->lan966x;
95 bool found = false;
96 u32 val;
97
98 val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port));
99
100 /* Collect all keysets for the port in a list */
101 if (l3_proto == ETH_P_ALL)
102 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
103
104 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_SNAP) {
105 if (ANA_VCAP_S2_CFG_SNAP_DIS_GET(val) & (BIT(0) << lookup))
106 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_LLC);
107 else
108 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_SNAP);
109
110 found = true;
111 }
112
113 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_CFM) {
114 if (ANA_VCAP_S2_CFG_OAM_DIS_GET(val) & (BIT(0) << lookup))
115 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
116 else
117 vcap_keyset_list_add(keysetlist, VCAP_KFS_OAM);
118
119 found = true;
120 }
121
122 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {
123 if (ANA_VCAP_S2_CFG_ARP_DIS_GET(val) & (BIT(0) << lookup))
124 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
125 else
126 vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);
127
128 found = true;
129 }
130
131 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
132 if (ANA_VCAP_S2_CFG_IP_OTHER_DIS_GET(val) & (BIT(0) << lookup))
133 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
134 else
135 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
136
137 if (ANA_VCAP_S2_CFG_IP_TCPUDP_DIS_GET(val) & (BIT(0) << lookup))
138 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
139 else
140 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
141
142 found = true;
143 }
144
145 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
146 switch (ANA_VCAP_S2_CFG_IP6_CFG_GET(val) & (0x3 << lookup)) {
147 case VCAP_IS2_PS_IPV6_TCPUDP_OTHER:
148 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_OTHER);
149 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_TCP_UDP);
150 break;
151 case VCAP_IS2_PS_IPV6_STD:
152 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);
153 break;
154 case VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER:
155 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
156 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
157 break;
158 case VCAP_IS2_PS_IPV6_MAC_ETYPE:
159 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
160 break;
161 }
162
163 found = true;
164 }
165
166 if (!found)
167 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
168
169 return 0;
170}
171
172static enum vcap_keyfield_set
173lan966x_vcap_validate_keyset(struct net_device *dev,
174 struct vcap_admin *admin,
175 struct vcap_rule *rule,
176 struct vcap_keyset_list *kslist,
177 u16 l3_proto)
178{
179 struct vcap_keyset_list keysetlist = {};
180 enum vcap_keyfield_set keysets[10] = {};
181 int lookup;
182 int err;
183
184 if (!kslist || kslist->cnt == 0)
185 return VCAP_KFS_NO_VALUE;
186
187 lookup = lan966x_vcap_cid_to_lookup(rule->vcap_chain_id);
188 keysetlist.max = ARRAY_SIZE(keysets);
189 keysetlist.keysets = keysets;
190 err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist,
191 l3_proto);
192 if (err)
193 return VCAP_KFS_NO_VALUE;
194
195 /* Check if there is a match and return the match */
196 for (int i = 0; i < kslist->cnt; ++i)
197 for (int j = 0; j < keysetlist.cnt; ++j)
198 if (kslist->keysets[i] == keysets[j])
199 return kslist->keysets[i];
200
201 return VCAP_KFS_NO_VALUE;
202}
203
204static bool lan966x_vcap_is_first_chain(struct vcap_rule *rule)
205{
206 return (rule->vcap_chain_id >= LAN966X_VCAP_CID_IS2_L0 &&
207 rule->vcap_chain_id < LAN966X_VCAP_CID_IS2_L1);
208}
209
210static void lan966x_vcap_add_default_fields(struct net_device *dev,
211 struct vcap_admin *admin,
212 struct vcap_rule *rule)
213{
214 struct lan966x_port *port = netdev_priv(dev);
215 u32 value, mask;
216
217 if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
218 &value, &mask))
219 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
220 ~BIT(port->chip_port));
221
222 if (lan966x_vcap_is_first_chain(rule))
223 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
224 VCAP_BIT_1);
225 else
226 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
227 VCAP_BIT_0);
228}
229
230static void lan966x_vcap_cache_erase(struct vcap_admin *admin)
231{
232 memset(admin->cache.keystream, 0, STREAMSIZE);
233 memset(admin->cache.maskstream, 0, STREAMSIZE);
234 memset(admin->cache.actionstream, 0, STREAMSIZE);
235 memset(&admin->cache.counter, 0, sizeof(admin->cache.counter));
236}
237
238static void lan966x_vcap_cache_write(struct net_device *dev,
239 struct vcap_admin *admin,
240 enum vcap_selection sel,
241 u32 start,
242 u32 count)
243{
244 struct lan966x_port *port = netdev_priv(dev);
245 struct lan966x *lan966x = port->lan966x;
246 u32 *keystr, *mskstr, *actstr;
247
248 keystr = &admin->cache.keystream[start];
249 mskstr = &admin->cache.maskstream[start];
250 actstr = &admin->cache.actionstream[start];
251
252 switch (sel) {
253 case VCAP_SEL_ENTRY:
254 for (int i = 0; i < count; ++i) {
255 lan_wr(keystr[i] & mskstr[i], lan966x,
256 VCAP_ENTRY_DAT(admin->tgt_inst, i));
257 lan_wr(~mskstr[i], lan966x,
258 VCAP_MASK_DAT(admin->tgt_inst, i));
259 }
260 break;
261 case VCAP_SEL_ACTION:
262 for (int i = 0; i < count; ++i)
263 lan_wr(actstr[i], lan966x,
264 VCAP_ACTION_DAT(admin->tgt_inst, i));
265 break;
266 case VCAP_SEL_COUNTER:
267 admin->cache.sticky = admin->cache.counter > 0;
268 lan_wr(admin->cache.counter, lan966x,
269 VCAP_CNT_DAT(admin->tgt_inst, 0));
270 break;
271 default:
272 break;
273 }
274}
275
276static void lan966x_vcap_cache_read(struct net_device *dev,
277 struct vcap_admin *admin,
278 enum vcap_selection sel,
279 u32 start,
280 u32 count)
281{
282 struct lan966x_port *port = netdev_priv(dev);
283 struct lan966x *lan966x = port->lan966x;
284 int instance = admin->tgt_inst;
285 u32 *keystr, *mskstr, *actstr;
286
287 keystr = &admin->cache.keystream[start];
288 mskstr = &admin->cache.maskstream[start];
289 actstr = &admin->cache.actionstream[start];
290
291 if (sel & VCAP_SEL_ENTRY) {
292 for (int i = 0; i < count; ++i) {
293 keystr[i] =
294 lan_rd(lan966x, VCAP_ENTRY_DAT(instance, i));
295 mskstr[i] =
296 ~lan_rd(lan966x, VCAP_MASK_DAT(instance, i));
297 }
298 }
299
300 if (sel & VCAP_SEL_ACTION)
301 for (int i = 0; i < count; ++i)
302 actstr[i] =
303 lan_rd(lan966x, VCAP_ACTION_DAT(instance, i));
304
305 if (sel & VCAP_SEL_COUNTER) {
306 admin->cache.counter =
307 lan_rd(lan966x, VCAP_CNT_DAT(instance, 0));
308 admin->cache.sticky = admin->cache.counter > 0;
309 }
310}
311
312static void lan966x_vcap_range_init(struct net_device *dev,
313 struct vcap_admin *admin,
314 u32 addr,
315 u32 count)
316{
317 struct lan966x_port *port = netdev_priv(dev);
318 struct lan966x *lan966x = port->lan966x;
319
320 __lan966x_vcap_range_init(lan966x, admin, addr, count);
321}
322
323static void lan966x_vcap_update(struct net_device *dev,
324 struct vcap_admin *admin,
325 enum vcap_command cmd,
326 enum vcap_selection sel,
327 u32 addr)
328{
329 struct lan966x_port *port = netdev_priv(dev);
330 struct lan966x *lan966x = port->lan966x;
331 bool clear;
332
333 clear = (cmd == VCAP_CMD_INITIALIZE);
334
335 lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
336 VCAP_MV_CFG_MV_SIZE_SET(0),
337 lan966x, VCAP_MV_CFG(admin->tgt_inst));
338
339 lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
340 VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |
341 VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |
342 VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |
343 VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
344 VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(clear) |
345 VCAP_UPDATE_CTRL_UPDATE_SHOT,
346 lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
347
348 lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
349}
350
351static void lan966x_vcap_move(struct net_device *dev,
352 struct vcap_admin *admin,
353 u32 addr, int offset, int count)
354{
355 struct lan966x_port *port = netdev_priv(dev);
356 struct lan966x *lan966x = port->lan966x;
357 enum vcap_command cmd;
358 u16 mv_num_pos;
359 u16 mv_size;
360
361 mv_size = count - 1;
362 if (offset > 0) {
363 mv_num_pos = offset - 1;
364 cmd = VCAP_CMD_MOVE_DOWN;
365 } else {
366 mv_num_pos = -offset - 1;
367 cmd = VCAP_CMD_MOVE_UP;
368 }
369
370 lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(mv_num_pos) |
371 VCAP_MV_CFG_MV_SIZE_SET(mv_size),
372 lan966x, VCAP_MV_CFG(admin->tgt_inst));
373
374 lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
375 VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
376 VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
377 VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
378 VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
379 VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(false) |
380 VCAP_UPDATE_CTRL_UPDATE_SHOT,
381 lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
382
383 lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
384}
385
386static int lan966x_vcap_port_info(struct net_device *dev,
387 struct vcap_admin *admin,
388 struct vcap_output_print *out)
389{
390 return 0;
391}
392
393static int lan966x_vcap_enable(struct net_device *dev,
394 struct vcap_admin *admin,
395 bool enable)
396{
397 struct lan966x_port *port = netdev_priv(dev);
398 struct lan966x *lan966x = port->lan966x;
399
400 lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(enable),
401 ANA_VCAP_S2_CFG_ENA,
402 lan966x, ANA_VCAP_S2_CFG(port->chip_port));
403
404 return 0;
405}
406
407static struct vcap_operations lan966x_vcap_ops = {
408 .validate_keyset = lan966x_vcap_validate_keyset,
409 .add_default_fields = lan966x_vcap_add_default_fields,
410 .cache_erase = lan966x_vcap_cache_erase,
411 .cache_write = lan966x_vcap_cache_write,
412 .cache_read = lan966x_vcap_cache_read,
413 .init = lan966x_vcap_range_init,
414 .update = lan966x_vcap_update,
415 .move = lan966x_vcap_move,
416 .port_info = lan966x_vcap_port_info,
417 .enable = lan966x_vcap_enable,
418};
419
420static void lan966x_vcap_admin_free(struct vcap_admin *admin)
421{
422 if (!admin)
423 return;
424
425 kfree(admin->cache.keystream);
426 kfree(admin->cache.maskstream);
427 kfree(admin->cache.actionstream);
428 mutex_destroy(&admin->lock);
429 kfree(admin);
430}
431
432static struct vcap_admin *
433lan966x_vcap_admin_alloc(struct lan966x *lan966x, struct vcap_control *ctrl,
434 const struct lan966x_vcap_inst *cfg)
435{
436 struct vcap_admin *admin;
437
438 admin = kzalloc(sizeof(*admin), GFP_KERNEL);
439 if (!admin)
440 return ERR_PTR(-ENOMEM);
441
442 mutex_init(&admin->lock);
443 INIT_LIST_HEAD(&admin->list);
444 INIT_LIST_HEAD(&admin->rules);
445 INIT_LIST_HEAD(&admin->enabled);
446
447 admin->vtype = cfg->vtype;
448 admin->vinst = 0;
449 admin->w32be = true;
450 admin->tgt_inst = cfg->tgt_inst;
451
452 admin->lookups = cfg->lookups;
453 admin->lookups_per_instance = cfg->lookups;
454
455 admin->first_cid = cfg->first_cid;
456 admin->last_cid = cfg->last_cid;
457
458 admin->cache.keystream = kzalloc(STREAMSIZE, GFP_KERNEL);
459 admin->cache.maskstream = kzalloc(STREAMSIZE, GFP_KERNEL);
460 admin->cache.actionstream = kzalloc(STREAMSIZE, GFP_KERNEL);
461 if (!admin->cache.keystream ||
462 !admin->cache.maskstream ||
463 !admin->cache.actionstream) {
464 lan966x_vcap_admin_free(admin);
465 return ERR_PTR(-ENOMEM);
466 }
467
468 return admin;
469}
470
471static void lan966x_vcap_block_init(struct lan966x *lan966x,
472 struct vcap_admin *admin,
473 struct lan966x_vcap_inst *cfg)
474{
475 admin->first_valid_addr = 0;
476 admin->last_used_addr = cfg->count;
477 admin->last_valid_addr = cfg->count - 1;
478
479 lan_wr(VCAP_CORE_IDX_CORE_IDX_SET(0),
480 lan966x, VCAP_CORE_IDX(admin->tgt_inst));
481 lan_wr(VCAP_CORE_MAP_CORE_MAP_SET(1),
482 lan966x, VCAP_CORE_MAP(admin->tgt_inst));
483
484 __lan966x_vcap_range_init(lan966x, admin, admin->first_valid_addr,
485 admin->last_valid_addr -
486 admin->first_valid_addr);
487}
488
489static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x,
490 struct vcap_admin *admin)
491{
492 for (int p = 0; p < lan966x->num_phys_ports; ++p)
493 lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p));
494}
495
496int lan966x_vcap_init(struct lan966x *lan966x)
497{
498 struct lan966x_vcap_inst *cfg;
499 struct vcap_control *ctrl;
500 struct vcap_admin *admin;
501
502 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
503 if (!ctrl)
504 return -ENOMEM;
505
506 ctrl->vcaps = lan966x_vcaps;
507 ctrl->stats = &lan966x_vcap_stats;
508 ctrl->ops = &lan966x_vcap_ops;
509
510 INIT_LIST_HEAD(&ctrl->list);
511 for (int i = 0; i < ARRAY_SIZE(lan966x_vcap_inst_cfg); ++i) {
512 cfg = &lan966x_vcap_inst_cfg[i];
513
514 admin = lan966x_vcap_admin_alloc(lan966x, ctrl, cfg);
515 if (IS_ERR(admin))
516 return PTR_ERR(admin);
517
518 lan966x_vcap_block_init(lan966x, admin, cfg);
519 lan966x_vcap_port_key_deselection(lan966x, admin);
520
521 list_add_tail(&admin->list, &ctrl->list);
522 }
523
524 lan966x->vcap_ctrl = ctrl;
525
526 return 0;
527}
528
529void lan966x_vcap_deinit(struct lan966x *lan966x)
530{
531 struct vcap_admin *admin, *admin_next;
532 struct vcap_control *ctrl;
533
534 ctrl = lan966x->vcap_ctrl;
535 if (!ctrl)
536 return;
537
538 list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) {
539 lan966x_vcap_port_key_deselection(lan966x, admin);
540 vcap_del_rules(ctrl, admin);
541 list_del(&admin->list);
542 lan966x_vcap_admin_free(admin);
543 }
544
545 kfree(ctrl);
546}