785 lines · c
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 312#define LAN966X_IS2_LOOKUPS 213#define LAN966X_ES0_LOOKUPS 114 15#define LAN966X_STAT_ESDX_GRN_BYTES 0x30016#define LAN966X_STAT_ESDX_GRN_PKTS 0x30117#define LAN966X_STAT_ESDX_YEL_BYTES 0x30218#define LAN966X_STAT_ESDX_YEL_PKTS 0x30319 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(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, 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 int124lan966x_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(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, VCAP_KFS_7TUPLE);139 break;140 case VCAP_IS1_PS_IPV4_5TUPLE_IP4:141 vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);142 break;143 case VCAP_IS1_PS_IPV4_NORMAL:144 vcap_keyset_list_add(keysetlist, 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, VCAP_KFS_NORMAL);154 vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL_IP6);155 break;156 case VCAP_IS1_PS_IPV6_5TUPLE_IP6:157 vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP6);158 break;159 case VCAP_IS1_PS_IPV6_7TUPLE:160 vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);161 break;162 case VCAP_IS1_PS_IPV6_5TUPLE_IP4:163 vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);164 break;165 case VCAP_IS1_PS_IPV6_DMAC_VID:166 vcap_keyset_list_add(keysetlist, 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, VCAP_KFS_7TUPLE);174 break;175 case VCAP_IS1_PS_OTHER_NORMAL:176 vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);177 break;178 }179 180 return 0;181}182 183static int184lan966x_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, 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, VCAP_KFS_MAC_LLC);202 else203 vcap_keyset_list_add(keysetlist, 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, VCAP_KFS_MAC_ETYPE);211 else212 vcap_keyset_list_add(keysetlist, 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, VCAP_KFS_MAC_ETYPE);220 else221 vcap_keyset_list_add(keysetlist, 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, VCAP_KFS_MAC_ETYPE);229 else230 vcap_keyset_list_add(keysetlist, 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, VCAP_KFS_MAC_ETYPE);234 else235 vcap_keyset_list_add(keysetlist, 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, VCAP_KFS_IP6_OTHER);244 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_TCP_UDP);245 break;246 case VCAP_IS2_PS_IPV6_STD:247 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);248 break;249 case VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER:250 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);251 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);252 break;253 case VCAP_IS2_PS_IPV6_MAC_ETYPE:254 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);255 break;256 }257 258 found = true;259 }260 261 if (!found)262 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);263 264 return 0;265}266 267static enum vcap_keyfield_set268lan966x_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(rule->vcap_chain_id);288 err = lan966x_vcap_is1_get_port_keysets(dev, lookup, &keysetlist,289 l3_proto);290 break;291 case VCAP_TYPE_IS2:292 lookup = lan966x_vcap_is2_cid_to_lookup(rule->vcap_chain_id);293 err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &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, VCAP_KF_IF_IGR_PORT_MASK,330 &value, &mask))331 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,332 ~BIT(port->chip_port));333 334 lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);335 vcap_rule_add_key_u32(rule, VCAP_KF_LOOKUP_INDEX, lookup, 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, VCAP_KF_IF_IGR_PORT_MASK,345 &value, &mask))346 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,347 ~BIT(port->chip_port));348 349 if (lan966x_vcap_is2_is_first_chain(rule))350 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,351 VCAP_BIT_1);352 else353 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,354 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, VCAP_KF_IF_EGR_PORT_NO,362 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 classified397 * with an ISDX > 0 (e.g by a rule in IS0). This is not mentioned in the398 * 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(&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(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_BYTES));423 lan_wr(admin->cache.counter, lan966x,424 SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS));425 lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_BYTES));426 lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS));427 mutex_unlock(&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(keystr[i] & mskstr[i], lan966x,448 VCAP_ENTRY_DAT(admin->tgt_inst, i));449 lan_wr(~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(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(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, 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, 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, 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, admin->tgt_inst);582}583 584static const 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(admin->cache.keystream);602 kfree(admin->cache.maskstream);603 kfree(admin->cache.actionstream);604 mutex_destroy(&admin->lock);605 kfree(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(sizeof(*admin), GFP_KERNEL);615 if (!admin)616 return ERR_PTR(-ENOMEM);617 618 mutex_init(&admin->lock);619 INIT_LIST_HEAD(&admin->list);620 INIT_LIST_HEAD(&admin->rules);621 INIT_LIST_HEAD(&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(-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, admin->first_valid_addr,662 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(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(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(&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(admin))729 return PTR_ERR(admin);730 731 lan966x_vcap_block_init(lan966x, admin, cfg);732 lan966x_vcap_port_key_deselection(lan966x, admin);733 734 list_add_tail(&admin->list, &ctrl->list);735 }736 737 dir = vcap_debugfs(lan966x->dev, lan966x->debugfs_root, ctrl);738 for (int p = 0; p < lan966x->num_phys_ports; ++p) {739 if (lan966x->ports[p]) {740 vcap_port_debugfs(lan966x->dev, dir, ctrl,741 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(ctrl, admin);779 list_del(&admin->list);780 lan966x_vcap_admin_free(admin);781 }782 783 kfree(ctrl);784}785