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