1 // SPDX-License-Identifier: GPL-2.0+ 2 /* Microchip Sparx5 Switch driver VCAP implementation 3 * 4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. 5 * 6 * The Sparx5 Chip Register Model can be browsed at this location: 7 * https://github.com/microchip-ung/sparx-5_reginfo 8 */ 9 10 #include <linux/types.h> 11 #include <linux/list.h> 12 13 #include "vcap_api.h" 14 #include "vcap_api_client.h" 15 #include "sparx5_main_regs.h" 16 #include "sparx5_main.h" 17 #include "sparx5_vcap_impl.h" 18 #include "sparx5_vcap_ag_api.h" 19 20 #define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */ 21 #define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */ 22 23 #define SPARX5_IS2_LOOKUPS 4 24 25 /* IS2 port keyset selection control */ 26 27 /* IS2 non-ethernet traffic type keyset generation */ 28 enum vcap_is2_port_sel_noneth { 29 VCAP_IS2_PS_NONETH_MAC_ETYPE, 30 VCAP_IS2_PS_NONETH_CUSTOM_1, 31 VCAP_IS2_PS_NONETH_CUSTOM_2, 32 VCAP_IS2_PS_NONETH_NO_LOOKUP 33 }; 34 35 /* IS2 IPv4 unicast traffic type keyset generation */ 36 enum vcap_is2_port_sel_ipv4_uc { 37 VCAP_IS2_PS_IPV4_UC_MAC_ETYPE, 38 VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER, 39 VCAP_IS2_PS_IPV4_UC_IP_7TUPLE, 40 }; 41 42 /* IS2 IPv4 multicast traffic type keyset generation */ 43 enum vcap_is2_port_sel_ipv4_mc { 44 VCAP_IS2_PS_IPV4_MC_MAC_ETYPE, 45 VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER, 46 VCAP_IS2_PS_IPV4_MC_IP_7TUPLE, 47 VCAP_IS2_PS_IPV4_MC_IP4_VID, 48 }; 49 50 /* IS2 IPv6 unicast traffic type keyset generation */ 51 enum vcap_is2_port_sel_ipv6_uc { 52 VCAP_IS2_PS_IPV6_UC_MAC_ETYPE, 53 VCAP_IS2_PS_IPV6_UC_IP_7TUPLE, 54 VCAP_IS2_PS_IPV6_UC_IP6_STD, 55 VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER, 56 }; 57 58 /* IS2 IPv6 multicast traffic type keyset generation */ 59 enum vcap_is2_port_sel_ipv6_mc { 60 VCAP_IS2_PS_IPV6_MC_MAC_ETYPE, 61 VCAP_IS2_PS_IPV6_MC_IP_7TUPLE, 62 VCAP_IS2_PS_IPV6_MC_IP6_VID, 63 VCAP_IS2_PS_IPV6_MC_IP6_STD, 64 VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER, 65 }; 66 67 /* IS2 ARP traffic type keyset generation */ 68 enum vcap_is2_port_sel_arp { 69 VCAP_IS2_PS_ARP_MAC_ETYPE, 70 VCAP_IS2_PS_ARP_ARP, 71 }; 72 73 static struct sparx5_vcap_inst { 74 enum vcap_type vtype; /* type of vcap */ 75 int vinst; /* instance number within the same type */ 76 int lookups; /* number of lookups in this vcap type */ 77 int lookups_per_instance; /* number of lookups in this instance */ 78 int first_cid; /* first chain id in this vcap */ 79 int last_cid; /* last chain id in this vcap */ 80 int count; /* number of available addresses, not in super vcap */ 81 int map_id; /* id in the super vcap block mapping (if applicable) */ 82 int blockno; /* starting block in super vcap (if applicable) */ 83 int blocks; /* number of blocks in super vcap (if applicable) */ 84 } sparx5_vcap_inst_cfg[] = { 85 { 86 .vtype = VCAP_TYPE_IS2, /* IS2-0 */ 87 .vinst = 0, 88 .map_id = 4, 89 .lookups = SPARX5_IS2_LOOKUPS, 90 .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2, 91 .first_cid = SPARX5_VCAP_CID_IS2_L0, 92 .last_cid = SPARX5_VCAP_CID_IS2_L2 - 1, 93 .blockno = 0, /* Maps block 0-1 */ 94 .blocks = 2, 95 }, 96 { 97 .vtype = VCAP_TYPE_IS2, /* IS2-1 */ 98 .vinst = 1, 99 .map_id = 5, 100 .lookups = SPARX5_IS2_LOOKUPS, 101 .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2, 102 .first_cid = SPARX5_VCAP_CID_IS2_L2, 103 .last_cid = SPARX5_VCAP_CID_IS2_MAX, 104 .blockno = 2, /* Maps block 2-3 */ 105 .blocks = 2, 106 }, 107 }; 108 109 /* Await the super VCAP completion of the current operation */ 110 static void sparx5_vcap_wait_super_update(struct sparx5 *sparx5) 111 { 112 u32 value; 113 114 read_poll_timeout(spx5_rd, value, 115 !VCAP_SUPER_CTRL_UPDATE_SHOT_GET(value), 500, 10000, 116 false, sparx5, VCAP_SUPER_CTRL); 117 } 118 119 /* Initializing a VCAP address range: only IS2 for now */ 120 static void _sparx5_vcap_range_init(struct sparx5 *sparx5, 121 struct vcap_admin *admin, 122 u32 addr, u32 count) 123 { 124 u32 size = count - 1; 125 126 spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) | 127 VCAP_SUPER_CFG_MV_SIZE_SET(size), 128 sparx5, VCAP_SUPER_CFG); 129 spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) | 130 VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) | 131 VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) | 132 VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) | 133 VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) | 134 VCAP_SUPER_CTRL_CLEAR_CACHE_SET(true) | 135 VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true), 136 sparx5, VCAP_SUPER_CTRL); 137 sparx5_vcap_wait_super_update(sparx5); 138 } 139 140 /* Initializing VCAP rule data area */ 141 static void sparx5_vcap_block_init(struct sparx5 *sparx5, 142 struct vcap_admin *admin) 143 { 144 _sparx5_vcap_range_init(sparx5, admin, admin->first_valid_addr, 145 admin->last_valid_addr - 146 admin->first_valid_addr); 147 } 148 149 /* Get the keyset name from the sparx5 VCAP model */ 150 static const char *sparx5_vcap_keyset_name(struct net_device *ndev, 151 enum vcap_keyfield_set keyset) 152 { 153 struct sparx5_port *port = netdev_priv(ndev); 154 155 return port->sparx5->vcap_ctrl->stats->keyfield_set_names[keyset]; 156 } 157 158 /* Check if this is the first lookup of IS2 */ 159 static bool sparx5_vcap_is2_is_first_chain(struct vcap_rule *rule) 160 { 161 return (rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L0 && 162 rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L1) || 163 ((rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L2 && 164 rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L3)); 165 } 166 167 /* Set the narrow range ingress port mask on a rule */ 168 static void sparx5_vcap_add_range_port_mask(struct vcap_rule *rule, 169 struct net_device *ndev) 170 { 171 struct sparx5_port *port = netdev_priv(ndev); 172 u32 port_mask; 173 u32 range; 174 175 range = port->portno / BITS_PER_TYPE(u32); 176 /* Port bit set to match-any */ 177 port_mask = ~BIT(port->portno % BITS_PER_TYPE(u32)); 178 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_SEL, 0, 0xf); 179 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_RNG, range, 0xf); 180 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0, port_mask); 181 } 182 183 /* Set the wide range ingress port mask on a rule */ 184 static void sparx5_vcap_add_wide_port_mask(struct vcap_rule *rule, 185 struct net_device *ndev) 186 { 187 struct sparx5_port *port = netdev_priv(ndev); 188 struct vcap_u72_key port_mask; 189 u32 range; 190 191 /* Port bit set to match-any */ 192 memset(port_mask.value, 0, sizeof(port_mask.value)); 193 memset(port_mask.mask, 0xff, sizeof(port_mask.mask)); 194 range = port->portno / BITS_PER_BYTE; 195 port_mask.mask[range] = ~BIT(port->portno % BITS_PER_BYTE); 196 vcap_rule_add_key_u72(rule, VCAP_KF_IF_IGR_PORT_MASK, &port_mask); 197 } 198 199 /* API callback used for validating a field keyset (check the port keysets) */ 200 static enum vcap_keyfield_set 201 sparx5_vcap_validate_keyset(struct net_device *ndev, 202 struct vcap_admin *admin, 203 struct vcap_rule *rule, 204 struct vcap_keyset_list *kslist, 205 u16 l3_proto) 206 { 207 if (!kslist || kslist->cnt == 0) 208 return VCAP_KFS_NO_VALUE; 209 /* for now just return whatever the API suggests */ 210 return kslist->keysets[0]; 211 } 212 213 /* API callback used for adding default fields to a rule */ 214 static void sparx5_vcap_add_default_fields(struct net_device *ndev, 215 struct vcap_admin *admin, 216 struct vcap_rule *rule) 217 { 218 const struct vcap_field *field; 219 220 field = vcap_lookup_keyfield(rule, VCAP_KF_IF_IGR_PORT_MASK); 221 if (field && field->width == SPX5_PORTS) 222 sparx5_vcap_add_wide_port_mask(rule, ndev); 223 else if (field && field->width == BITS_PER_TYPE(u32)) 224 sparx5_vcap_add_range_port_mask(rule, ndev); 225 else 226 pr_err("%s:%d: %s: could not add an ingress port mask for: %s\n", 227 __func__, __LINE__, netdev_name(ndev), 228 sparx5_vcap_keyset_name(ndev, rule->keyset)); 229 /* add the lookup bit */ 230 if (sparx5_vcap_is2_is_first_chain(rule)) 231 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_1); 232 else 233 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_0); 234 } 235 236 /* API callback used for erasing the vcap cache area (not the register area) */ 237 static void sparx5_vcap_cache_erase(struct vcap_admin *admin) 238 { 239 memset(admin->cache.keystream, 0, STREAMSIZE); 240 memset(admin->cache.maskstream, 0, STREAMSIZE); 241 memset(admin->cache.actionstream, 0, STREAMSIZE); 242 memset(&admin->cache.counter, 0, sizeof(admin->cache.counter)); 243 } 244 245 /* API callback used for writing to the VCAP cache */ 246 static void sparx5_vcap_cache_write(struct net_device *ndev, 247 struct vcap_admin *admin, 248 enum vcap_selection sel, 249 u32 start, 250 u32 count) 251 { 252 struct sparx5_port *port = netdev_priv(ndev); 253 struct sparx5 *sparx5 = port->sparx5; 254 u32 *keystr, *mskstr, *actstr; 255 int idx; 256 257 keystr = &admin->cache.keystream[start]; 258 mskstr = &admin->cache.maskstream[start]; 259 actstr = &admin->cache.actionstream[start]; 260 switch (sel) { 261 case VCAP_SEL_ENTRY: 262 for (idx = 0; idx < count; ++idx) { 263 /* Avoid 'match-off' by setting value & mask */ 264 spx5_wr(keystr[idx] & mskstr[idx], sparx5, 265 VCAP_SUPER_VCAP_ENTRY_DAT(idx)); 266 spx5_wr(~mskstr[idx], sparx5, 267 VCAP_SUPER_VCAP_MASK_DAT(idx)); 268 } 269 break; 270 case VCAP_SEL_ACTION: 271 for (idx = 0; idx < count; ++idx) 272 spx5_wr(actstr[idx], sparx5, 273 VCAP_SUPER_VCAP_ACTION_DAT(idx)); 274 break; 275 case VCAP_SEL_ALL: 276 pr_err("%s:%d: cannot write all streams at once\n", 277 __func__, __LINE__); 278 break; 279 default: 280 break; 281 } 282 } 283 284 /* API callback used for reading from the VCAP into the VCAP cache */ 285 static void sparx5_vcap_cache_read(struct net_device *ndev, 286 struct vcap_admin *admin, 287 enum vcap_selection sel, u32 start, 288 u32 count) 289 { 290 /* this will be added later */ 291 } 292 293 /* API callback used for initializing a VCAP address range */ 294 static void sparx5_vcap_range_init(struct net_device *ndev, 295 struct vcap_admin *admin, u32 addr, 296 u32 count) 297 { 298 struct sparx5_port *port = netdev_priv(ndev); 299 struct sparx5 *sparx5 = port->sparx5; 300 301 _sparx5_vcap_range_init(sparx5, admin, addr, count); 302 } 303 304 /* API callback used for updating the VCAP cache */ 305 static void sparx5_vcap_update(struct net_device *ndev, 306 struct vcap_admin *admin, enum vcap_command cmd, 307 enum vcap_selection sel, u32 addr) 308 { 309 struct sparx5_port *port = netdev_priv(ndev); 310 struct sparx5 *sparx5 = port->sparx5; 311 bool clear; 312 313 clear = (cmd == VCAP_CMD_INITIALIZE); 314 spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) | 315 VCAP_SUPER_CFG_MV_SIZE_SET(0), sparx5, VCAP_SUPER_CFG); 316 spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) | 317 VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) | 318 VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) | 319 VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) | 320 VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) | 321 VCAP_SUPER_CTRL_CLEAR_CACHE_SET(clear) | 322 VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true), 323 sparx5, VCAP_SUPER_CTRL); 324 sparx5_vcap_wait_super_update(sparx5); 325 } 326 327 /* API callback used for moving a block of rules in the VCAP */ 328 static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin, 329 u32 addr, int offset, int count) 330 { 331 /* this will be added later */ 332 } 333 334 /* Provide port information via a callback interface */ 335 static int sparx5_port_info(struct net_device *ndev, enum vcap_type vtype, 336 int (*pf)(void *out, int arg, const char *fmt, ...), 337 void *out, int arg) 338 { 339 /* this will be added later */ 340 return 0; 341 } 342 343 /* API callback operations: only IS2 is supported for now */ 344 static struct vcap_operations sparx5_vcap_ops = { 345 .validate_keyset = sparx5_vcap_validate_keyset, 346 .add_default_fields = sparx5_vcap_add_default_fields, 347 .cache_erase = sparx5_vcap_cache_erase, 348 .cache_write = sparx5_vcap_cache_write, 349 .cache_read = sparx5_vcap_cache_read, 350 .init = sparx5_vcap_range_init, 351 .update = sparx5_vcap_update, 352 .move = sparx5_vcap_move, 353 .port_info = sparx5_port_info, 354 }; 355 356 /* Enable lookups per port and set the keyset generation: only IS2 for now */ 357 static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5, 358 struct vcap_admin *admin) 359 { 360 int portno, lookup; 361 u32 keysel; 362 363 /* enable all 4 lookups on all ports */ 364 for (portno = 0; portno < SPX5_PORTS; ++portno) 365 spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5, 366 ANA_ACL_VCAP_S2_CFG(portno)); 367 368 /* all traffic types generate the MAC_ETYPE keyset for now in all 369 * lookups on all ports 370 */ 371 keysel = ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(true) | 372 ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(VCAP_IS2_PS_NONETH_MAC_ETYPE) | 373 ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_MC_MAC_ETYPE) | 374 ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_UC_MAC_ETYPE) | 375 ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_MC_MAC_ETYPE) | 376 ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_UC_MAC_ETYPE) | 377 ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(VCAP_IS2_PS_ARP_MAC_ETYPE); 378 for (lookup = 0; lookup < admin->lookups; ++lookup) { 379 for (portno = 0; portno < SPX5_PORTS; ++portno) { 380 spx5_wr(keysel, sparx5, 381 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 382 } 383 } 384 } 385 386 /* Disable lookups per port and set the keyset generation: only IS2 for now */ 387 static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5, 388 struct vcap_admin *admin) 389 { 390 int portno; 391 392 for (portno = 0; portno < SPX5_PORTS; ++portno) 393 spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), 394 ANA_ACL_VCAP_S2_CFG_SEC_ENA, 395 sparx5, 396 ANA_ACL_VCAP_S2_CFG(portno)); 397 } 398 399 static void sparx5_vcap_admin_free(struct vcap_admin *admin) 400 { 401 if (!admin) 402 return; 403 kfree(admin->cache.keystream); 404 kfree(admin->cache.maskstream); 405 kfree(admin->cache.actionstream); 406 kfree(admin); 407 } 408 409 /* Allocate a vcap instance with a rule list and a cache area */ 410 static struct vcap_admin * 411 sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl, 412 const struct sparx5_vcap_inst *cfg) 413 { 414 struct vcap_admin *admin; 415 416 admin = kzalloc(sizeof(*admin), GFP_KERNEL); 417 if (!admin) 418 return ERR_PTR(-ENOMEM); 419 INIT_LIST_HEAD(&admin->list); 420 INIT_LIST_HEAD(&admin->rules); 421 admin->vtype = cfg->vtype; 422 admin->vinst = cfg->vinst; 423 admin->lookups = cfg->lookups; 424 admin->lookups_per_instance = cfg->lookups_per_instance; 425 admin->first_cid = cfg->first_cid; 426 admin->last_cid = cfg->last_cid; 427 admin->cache.keystream = 428 kzalloc(STREAMSIZE, GFP_KERNEL); 429 admin->cache.maskstream = 430 kzalloc(STREAMSIZE, GFP_KERNEL); 431 admin->cache.actionstream = 432 kzalloc(STREAMSIZE, GFP_KERNEL); 433 if (!admin->cache.keystream || !admin->cache.maskstream || 434 !admin->cache.actionstream) { 435 sparx5_vcap_admin_free(admin); 436 return ERR_PTR(-ENOMEM); 437 } 438 return admin; 439 } 440 441 /* Do block allocations and provide addresses for VCAP instances */ 442 static void sparx5_vcap_block_alloc(struct sparx5 *sparx5, 443 struct vcap_admin *admin, 444 const struct sparx5_vcap_inst *cfg) 445 { 446 int idx; 447 448 /* Super VCAP block mapping and address configuration. Block 0 449 * is assigned addresses 0 through 3071, block 1 is assigned 450 * addresses 3072 though 6143, and so on. 451 */ 452 for (idx = cfg->blockno; idx < cfg->blockno + cfg->blocks; ++idx) { 453 spx5_wr(VCAP_SUPER_IDX_CORE_IDX_SET(idx), sparx5, 454 VCAP_SUPER_IDX); 455 spx5_wr(VCAP_SUPER_MAP_CORE_MAP_SET(cfg->map_id), sparx5, 456 VCAP_SUPER_MAP); 457 } 458 admin->first_valid_addr = cfg->blockno * SUPER_VCAP_BLK_SIZE; 459 admin->last_used_addr = admin->first_valid_addr + 460 cfg->blocks * SUPER_VCAP_BLK_SIZE; 461 admin->last_valid_addr = admin->last_used_addr - 1; 462 } 463 464 /* Allocate a vcap control and vcap instances and configure the system */ 465 int sparx5_vcap_init(struct sparx5 *sparx5) 466 { 467 const struct sparx5_vcap_inst *cfg; 468 struct vcap_control *ctrl; 469 struct vcap_admin *admin; 470 int err = 0, idx; 471 472 /* Create a VCAP control instance that owns the platform specific VCAP 473 * model with VCAP instances and information about keysets, keys, 474 * actionsets and actions 475 * - Create administrative state for each available VCAP 476 * - Lists of rules 477 * - Address information 478 * - Initialize VCAP blocks 479 * - Configure port keysets 480 */ 481 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); 482 if (!ctrl) 483 return -ENOMEM; 484 485 sparx5->vcap_ctrl = ctrl; 486 /* select the sparx5 VCAP model */ 487 ctrl->vcaps = sparx5_vcaps; 488 ctrl->stats = &sparx5_vcap_stats; 489 /* Setup callbacks to allow the API to use the VCAP HW */ 490 ctrl->ops = &sparx5_vcap_ops; 491 492 INIT_LIST_HEAD(&ctrl->list); 493 for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) { 494 cfg = &sparx5_vcap_inst_cfg[idx]; 495 admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg); 496 if (IS_ERR(admin)) { 497 err = PTR_ERR(admin); 498 pr_err("%s:%d: vcap allocation failed: %d\n", 499 __func__, __LINE__, err); 500 return err; 501 } 502 sparx5_vcap_block_alloc(sparx5, admin, cfg); 503 sparx5_vcap_block_init(sparx5, admin); 504 if (cfg->vinst == 0) 505 sparx5_vcap_port_key_selection(sparx5, admin); 506 list_add_tail(&admin->list, &ctrl->list); 507 } 508 509 return err; 510 } 511 512 void sparx5_vcap_destroy(struct sparx5 *sparx5) 513 { 514 struct vcap_control *ctrl = sparx5->vcap_ctrl; 515 struct vcap_admin *admin, *admin_next; 516 517 if (!ctrl) 518 return; 519 520 list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) { 521 sparx5_vcap_port_key_deselection(sparx5, admin); 522 vcap_del_rules(ctrl, admin); 523 list_del(&admin->list); 524 sparx5_vcap_admin_free(admin); 525 } 526 kfree(ctrl); 527 } 528