| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784 |
- // SPDX-License-Identifier: GPL-2.0+
- #include "lan966x_main.h"
- #include "lan966x_vcap_ag_api.h"
- #include "vcap_api.h"
- #include "vcap_api_client.h"
- #include "vcap_api_debugfs.h"
- #define STREAMSIZE (64 * 4)
- #define LAN966X_IS1_LOOKUPS 3
- #define LAN966X_IS2_LOOKUPS 2
- #define LAN966X_ES0_LOOKUPS 1
- #define LAN966X_STAT_ESDX_GRN_BYTES 0x300
- #define LAN966X_STAT_ESDX_GRN_PKTS 0x301
- #define LAN966X_STAT_ESDX_YEL_BYTES 0x302
- #define LAN966X_STAT_ESDX_YEL_PKTS 0x303
- static struct lan966x_vcap_inst {
- enum vcap_type vtype; /* type of vcap */
- int tgt_inst; /* hardware instance number */
- int lookups; /* number of lookups in this vcap type */
- int first_cid; /* first chain id in this vcap */
- int last_cid; /* last chain id in this vcap */
- int count; /* number of available addresses */
- bool ingress; /* is vcap in the ingress path */
- } lan966x_vcap_inst_cfg[] = {
- {
- .vtype = VCAP_TYPE_ES0,
- .tgt_inst = 0,
- .lookups = LAN966X_ES0_LOOKUPS,
- .first_cid = LAN966X_VCAP_CID_ES0_L0,
- .last_cid = LAN966X_VCAP_CID_ES0_MAX,
- .count = 64,
- },
- {
- .vtype = VCAP_TYPE_IS1, /* IS1-0 */
- .tgt_inst = 1,
- .lookups = LAN966X_IS1_LOOKUPS,
- .first_cid = LAN966X_VCAP_CID_IS1_L0,
- .last_cid = LAN966X_VCAP_CID_IS1_MAX,
- .count = 768,
- .ingress = true,
- },
- {
- .vtype = VCAP_TYPE_IS2, /* IS2-0 */
- .tgt_inst = 2,
- .lookups = LAN966X_IS2_LOOKUPS,
- .first_cid = LAN966X_VCAP_CID_IS2_L0,
- .last_cid = LAN966X_VCAP_CID_IS2_MAX,
- .count = 256,
- .ingress = true,
- },
- };
- struct lan966x_vcap_cmd_cb {
- struct lan966x *lan966x;
- u32 instance;
- };
- static u32 lan966x_vcap_read_update_ctrl(const struct lan966x_vcap_cmd_cb *cb)
- {
- return lan_rd(cb->lan966x, VCAP_UPDATE_CTRL(cb->instance));
- }
- static void lan966x_vcap_wait_update(struct lan966x *lan966x, int instance)
- {
- const struct lan966x_vcap_cmd_cb cb = { .lan966x = lan966x,
- .instance = instance };
- u32 val;
- readx_poll_timeout(lan966x_vcap_read_update_ctrl, &cb, val,
- (val & VCAP_UPDATE_CTRL_UPDATE_SHOT) == 0, 10,
- 100000);
- }
- static void __lan966x_vcap_range_init(struct lan966x *lan966x,
- struct vcap_admin *admin,
- u32 addr,
- u32 count)
- {
- lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
- VCAP_MV_CFG_MV_SIZE_SET(count - 1),
- lan966x, VCAP_MV_CFG(admin->tgt_inst));
- lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |
- VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
- VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
- VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
- VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
- VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(true) |
- VCAP_UPDATE_CTRL_UPDATE_SHOT_SET(1),
- lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
- lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
- }
- static int lan966x_vcap_is1_cid_to_lookup(int cid)
- {
- int lookup = 0;
- if (cid >= LAN966X_VCAP_CID_IS1_L1 &&
- cid < LAN966X_VCAP_CID_IS1_L2)
- lookup = 1;
- else if (cid >= LAN966X_VCAP_CID_IS1_L2 &&
- cid < LAN966X_VCAP_CID_IS1_MAX)
- lookup = 2;
- return lookup;
- }
- static int lan966x_vcap_is2_cid_to_lookup(int cid)
- {
- if (cid >= LAN966X_VCAP_CID_IS2_L1 &&
- cid < LAN966X_VCAP_CID_IS2_MAX)
- return 1;
- return 0;
- }
- /* Return the list of keysets for the vcap port configuration */
- static int
- lan966x_vcap_is1_get_port_keysets(struct net_device *ndev, int lookup,
- struct vcap_keyset_list *keysetlist,
- u16 l3_proto)
- {
- struct lan966x_port *port = netdev_priv(ndev);
- struct lan966x *lan966x = port->lan966x;
- u32 val;
- val = lan_rd(lan966x, ANA_VCAP_S1_CFG(port->chip_port, lookup));
- /* Collect all keysets for the port in a list */
- if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
- switch (ANA_VCAP_S1_CFG_KEY_IP4_CFG_GET(val)) {
- case VCAP_IS1_PS_IPV4_7TUPLE:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
- break;
- case VCAP_IS1_PS_IPV4_5TUPLE_IP4:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);
- break;
- case VCAP_IS1_PS_IPV4_NORMAL:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
- break;
- }
- }
- if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
- switch (ANA_VCAP_S1_CFG_KEY_IP6_CFG_GET(val)) {
- case VCAP_IS1_PS_IPV6_NORMAL:
- case VCAP_IS1_PS_IPV6_NORMAL_IP6:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
- vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL_IP6);
- break;
- case VCAP_IS1_PS_IPV6_5TUPLE_IP6:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP6);
- break;
- case VCAP_IS1_PS_IPV6_7TUPLE:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
- break;
- case VCAP_IS1_PS_IPV6_5TUPLE_IP4:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);
- break;
- case VCAP_IS1_PS_IPV6_DMAC_VID:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_DMAC_VID);
- break;
- }
- }
- switch (ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(val)) {
- case VCAP_IS1_PS_OTHER_7TUPLE:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
- break;
- case VCAP_IS1_PS_OTHER_NORMAL:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
- break;
- }
- return 0;
- }
- static int
- lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup,
- struct vcap_keyset_list *keysetlist,
- u16 l3_proto)
- {
- struct lan966x_port *port = netdev_priv(dev);
- struct lan966x *lan966x = port->lan966x;
- bool found = false;
- u32 val;
- val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port));
- /* Collect all keysets for the port in a list */
- if (l3_proto == ETH_P_ALL)
- vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
- if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_SNAP) {
- if (ANA_VCAP_S2_CFG_SNAP_DIS_GET(val) & (BIT(0) << lookup))
- vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_LLC);
- else
- vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_SNAP);
- found = true;
- }
- if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_CFM) {
- if (ANA_VCAP_S2_CFG_OAM_DIS_GET(val) & (BIT(0) << lookup))
- vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
- else
- vcap_keyset_list_add(keysetlist, VCAP_KFS_OAM);
- found = true;
- }
- if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {
- if (ANA_VCAP_S2_CFG_ARP_DIS_GET(val) & (BIT(0) << lookup))
- vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
- else
- vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);
- found = true;
- }
- if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
- if (ANA_VCAP_S2_CFG_IP_OTHER_DIS_GET(val) & (BIT(0) << lookup))
- vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
- else
- vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
- if (ANA_VCAP_S2_CFG_IP_TCPUDP_DIS_GET(val) & (BIT(0) << lookup))
- vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
- else
- vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
- found = true;
- }
- if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
- switch (ANA_VCAP_S2_CFG_IP6_CFG_GET(val) & (0x3 << lookup)) {
- case VCAP_IS2_PS_IPV6_TCPUDP_OTHER:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_OTHER);
- vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_TCP_UDP);
- break;
- case VCAP_IS2_PS_IPV6_STD:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);
- break;
- case VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
- vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
- break;
- case VCAP_IS2_PS_IPV6_MAC_ETYPE:
- vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
- break;
- }
- found = true;
- }
- if (!found)
- vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
- return 0;
- }
- 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)
- {
- struct vcap_keyset_list keysetlist = {};
- enum vcap_keyfield_set keysets[10] = {};
- int lookup;
- int err;
- if (!kslist || kslist->cnt == 0)
- return VCAP_KFS_NO_VALUE;
- keysetlist.max = ARRAY_SIZE(keysets);
- keysetlist.keysets = keysets;
- switch (admin->vtype) {
- case VCAP_TYPE_IS1:
- lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);
- err = lan966x_vcap_is1_get_port_keysets(dev, lookup, &keysetlist,
- l3_proto);
- break;
- case VCAP_TYPE_IS2:
- lookup = lan966x_vcap_is2_cid_to_lookup(rule->vcap_chain_id);
- err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist,
- l3_proto);
- break;
- case VCAP_TYPE_ES0:
- return kslist->keysets[0];
- default:
- pr_err("vcap type: %s not supported\n",
- lan966x_vcaps[admin->vtype].name);
- return VCAP_KFS_NO_VALUE;
- }
- if (err)
- return VCAP_KFS_NO_VALUE;
- /* Check if there is a match and return the match */
- for (int i = 0; i < kslist->cnt; ++i)
- for (int j = 0; j < keysetlist.cnt; ++j)
- if (kslist->keysets[i] == keysets[j])
- return kslist->keysets[i];
- return VCAP_KFS_NO_VALUE;
- }
- static bool lan966x_vcap_is2_is_first_chain(struct vcap_rule *rule)
- {
- return (rule->vcap_chain_id >= LAN966X_VCAP_CID_IS2_L0 &&
- rule->vcap_chain_id < LAN966X_VCAP_CID_IS2_L1);
- }
- static void lan966x_vcap_is1_add_default_fields(struct lan966x_port *port,
- struct vcap_admin *admin,
- struct vcap_rule *rule)
- {
- u32 value, mask;
- u32 lookup;
- if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
- &value, &mask))
- vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
- ~BIT(port->chip_port));
- lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);
- vcap_rule_add_key_u32(rule, VCAP_KF_LOOKUP_INDEX, lookup, 0x3);
- }
- static void lan966x_vcap_is2_add_default_fields(struct lan966x_port *port,
- struct vcap_admin *admin,
- struct vcap_rule *rule)
- {
- u32 value, mask;
- if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
- &value, &mask))
- vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
- ~BIT(port->chip_port));
- if (lan966x_vcap_is2_is_first_chain(rule))
- vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
- VCAP_BIT_1);
- else
- vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
- VCAP_BIT_0);
- }
- static void lan966x_vcap_es0_add_default_fields(struct lan966x_port *port,
- struct vcap_admin *admin,
- struct vcap_rule *rule)
- {
- vcap_rule_add_key_u32(rule, VCAP_KF_IF_EGR_PORT_NO,
- port->chip_port, GENMASK(4, 0));
- }
- static void lan966x_vcap_add_default_fields(struct net_device *dev,
- struct vcap_admin *admin,
- struct vcap_rule *rule)
- {
- struct lan966x_port *port = netdev_priv(dev);
- switch (admin->vtype) {
- case VCAP_TYPE_IS1:
- lan966x_vcap_is1_add_default_fields(port, admin, rule);
- break;
- case VCAP_TYPE_IS2:
- lan966x_vcap_is2_add_default_fields(port, admin, rule);
- break;
- case VCAP_TYPE_ES0:
- lan966x_vcap_es0_add_default_fields(port, admin, rule);
- break;
- default:
- pr_err("vcap type: %s not supported\n",
- lan966x_vcaps[admin->vtype].name);
- break;
- }
- }
- static void lan966x_vcap_cache_erase(struct vcap_admin *admin)
- {
- memset(admin->cache.keystream, 0, STREAMSIZE);
- memset(admin->cache.maskstream, 0, STREAMSIZE);
- memset(admin->cache.actionstream, 0, STREAMSIZE);
- memset(&admin->cache.counter, 0, sizeof(admin->cache.counter));
- }
- /* The ESDX counter is only used/incremented if the frame has been classified
- * with an ISDX > 0 (e.g by a rule in IS0). This is not mentioned in the
- * datasheet.
- */
- static void lan966x_es0_read_esdx_counter(struct lan966x *lan966x,
- struct vcap_admin *admin, u32 id)
- {
- u32 counter;
- id = id & 0xff; /* counter limit */
- spin_lock(&lan966x->stats_lock);
- lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG);
- counter = lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS)) +
- lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS));
- spin_unlock(&lan966x->stats_lock);
- if (counter)
- admin->cache.counter = counter;
- }
- static void lan966x_es0_write_esdx_counter(struct lan966x *lan966x,
- struct vcap_admin *admin, u32 id)
- {
- id = id & 0xff; /* counter limit */
- spin_lock(&lan966x->stats_lock);
- lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG);
- lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_BYTES));
- lan_wr(admin->cache.counter, lan966x,
- SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS));
- lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_BYTES));
- lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS));
- spin_unlock(&lan966x->stats_lock);
- }
- static void lan966x_vcap_cache_write(struct net_device *dev,
- struct vcap_admin *admin,
- enum vcap_selection sel,
- u32 start,
- u32 count)
- {
- struct lan966x_port *port = netdev_priv(dev);
- struct lan966x *lan966x = port->lan966x;
- u32 *keystr, *mskstr, *actstr;
- keystr = &admin->cache.keystream[start];
- mskstr = &admin->cache.maskstream[start];
- actstr = &admin->cache.actionstream[start];
- switch (sel) {
- case VCAP_SEL_ENTRY:
- for (int i = 0; i < count; ++i) {
- lan_wr(keystr[i] & mskstr[i], lan966x,
- VCAP_ENTRY_DAT(admin->tgt_inst, i));
- lan_wr(~mskstr[i], lan966x,
- VCAP_MASK_DAT(admin->tgt_inst, i));
- }
- break;
- case VCAP_SEL_ACTION:
- for (int i = 0; i < count; ++i)
- lan_wr(actstr[i], lan966x,
- VCAP_ACTION_DAT(admin->tgt_inst, i));
- break;
- case VCAP_SEL_COUNTER:
- admin->cache.sticky = admin->cache.counter > 0;
- lan_wr(admin->cache.counter, lan966x,
- VCAP_CNT_DAT(admin->tgt_inst, 0));
- if (admin->vtype == VCAP_TYPE_ES0)
- lan966x_es0_write_esdx_counter(lan966x, admin, start);
- break;
- default:
- break;
- }
- }
- static void lan966x_vcap_cache_read(struct net_device *dev,
- struct vcap_admin *admin,
- enum vcap_selection sel,
- u32 start,
- u32 count)
- {
- struct lan966x_port *port = netdev_priv(dev);
- struct lan966x *lan966x = port->lan966x;
- int instance = admin->tgt_inst;
- u32 *keystr, *mskstr, *actstr;
- keystr = &admin->cache.keystream[start];
- mskstr = &admin->cache.maskstream[start];
- actstr = &admin->cache.actionstream[start];
- if (sel & VCAP_SEL_ENTRY) {
- for (int i = 0; i < count; ++i) {
- keystr[i] =
- lan_rd(lan966x, VCAP_ENTRY_DAT(instance, i));
- mskstr[i] =
- ~lan_rd(lan966x, VCAP_MASK_DAT(instance, i));
- }
- }
- if (sel & VCAP_SEL_ACTION)
- for (int i = 0; i < count; ++i)
- actstr[i] =
- lan_rd(lan966x, VCAP_ACTION_DAT(instance, i));
- if (sel & VCAP_SEL_COUNTER) {
- admin->cache.counter =
- lan_rd(lan966x, VCAP_CNT_DAT(instance, 0));
- admin->cache.sticky = admin->cache.counter > 0;
- if (admin->vtype == VCAP_TYPE_ES0)
- lan966x_es0_read_esdx_counter(lan966x, admin, start);
- }
- }
- static void lan966x_vcap_range_init(struct net_device *dev,
- struct vcap_admin *admin,
- u32 addr,
- u32 count)
- {
- struct lan966x_port *port = netdev_priv(dev);
- struct lan966x *lan966x = port->lan966x;
- __lan966x_vcap_range_init(lan966x, admin, addr, count);
- }
- static void lan966x_vcap_update(struct net_device *dev,
- struct vcap_admin *admin,
- enum vcap_command cmd,
- enum vcap_selection sel,
- u32 addr)
- {
- struct lan966x_port *port = netdev_priv(dev);
- struct lan966x *lan966x = port->lan966x;
- bool clear;
- clear = (cmd == VCAP_CMD_INITIALIZE);
- lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
- VCAP_MV_CFG_MV_SIZE_SET(0),
- lan966x, VCAP_MV_CFG(admin->tgt_inst));
- lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
- VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |
- VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |
- VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |
- VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
- VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(clear) |
- VCAP_UPDATE_CTRL_UPDATE_SHOT,
- lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
- lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
- }
- static void lan966x_vcap_move(struct net_device *dev,
- struct vcap_admin *admin,
- u32 addr, int offset, int count)
- {
- struct lan966x_port *port = netdev_priv(dev);
- struct lan966x *lan966x = port->lan966x;
- enum vcap_command cmd;
- u16 mv_num_pos;
- u16 mv_size;
- mv_size = count - 1;
- if (offset > 0) {
- mv_num_pos = offset - 1;
- cmd = VCAP_CMD_MOVE_DOWN;
- } else {
- mv_num_pos = -offset - 1;
- cmd = VCAP_CMD_MOVE_UP;
- }
- lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(mv_num_pos) |
- VCAP_MV_CFG_MV_SIZE_SET(mv_size),
- lan966x, VCAP_MV_CFG(admin->tgt_inst));
- lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
- VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
- VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
- VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
- VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
- VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(false) |
- VCAP_UPDATE_CTRL_UPDATE_SHOT,
- lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
- lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
- }
- static const struct vcap_operations lan966x_vcap_ops = {
- .validate_keyset = lan966x_vcap_validate_keyset,
- .add_default_fields = lan966x_vcap_add_default_fields,
- .cache_erase = lan966x_vcap_cache_erase,
- .cache_write = lan966x_vcap_cache_write,
- .cache_read = lan966x_vcap_cache_read,
- .init = lan966x_vcap_range_init,
- .update = lan966x_vcap_update,
- .move = lan966x_vcap_move,
- .port_info = lan966x_vcap_port_info,
- };
- static void lan966x_vcap_admin_free(struct vcap_admin *admin)
- {
- if (!admin)
- return;
- kfree(admin->cache.keystream);
- kfree(admin->cache.maskstream);
- kfree(admin->cache.actionstream);
- mutex_destroy(&admin->lock);
- kfree(admin);
- }
- static struct vcap_admin *
- lan966x_vcap_admin_alloc(struct lan966x *lan966x, struct vcap_control *ctrl,
- const struct lan966x_vcap_inst *cfg)
- {
- struct vcap_admin *admin;
- admin = kzalloc_obj(*admin);
- if (!admin)
- return ERR_PTR(-ENOMEM);
- mutex_init(&admin->lock);
- INIT_LIST_HEAD(&admin->list);
- INIT_LIST_HEAD(&admin->rules);
- INIT_LIST_HEAD(&admin->enabled);
- admin->vtype = cfg->vtype;
- admin->vinst = 0;
- admin->ingress = cfg->ingress;
- admin->w32be = true;
- admin->tgt_inst = cfg->tgt_inst;
- admin->lookups = cfg->lookups;
- admin->lookups_per_instance = cfg->lookups;
- admin->first_cid = cfg->first_cid;
- admin->last_cid = cfg->last_cid;
- admin->cache.keystream = kzalloc(STREAMSIZE, GFP_KERNEL);
- admin->cache.maskstream = kzalloc(STREAMSIZE, GFP_KERNEL);
- admin->cache.actionstream = kzalloc(STREAMSIZE, GFP_KERNEL);
- if (!admin->cache.keystream ||
- !admin->cache.maskstream ||
- !admin->cache.actionstream) {
- lan966x_vcap_admin_free(admin);
- return ERR_PTR(-ENOMEM);
- }
- return admin;
- }
- static void lan966x_vcap_block_init(struct lan966x *lan966x,
- struct vcap_admin *admin,
- struct lan966x_vcap_inst *cfg)
- {
- admin->first_valid_addr = 0;
- admin->last_used_addr = cfg->count;
- admin->last_valid_addr = cfg->count - 1;
- lan_wr(VCAP_CORE_IDX_CORE_IDX_SET(0),
- lan966x, VCAP_CORE_IDX(admin->tgt_inst));
- lan_wr(VCAP_CORE_MAP_CORE_MAP_SET(1),
- lan966x, VCAP_CORE_MAP(admin->tgt_inst));
- __lan966x_vcap_range_init(lan966x, admin, admin->first_valid_addr,
- admin->last_valid_addr -
- admin->first_valid_addr);
- }
- static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x,
- struct vcap_admin *admin)
- {
- u32 val;
- switch (admin->vtype) {
- case VCAP_TYPE_IS1:
- val = ANA_VCAP_S1_CFG_KEY_IP6_CFG_SET(VCAP_IS1_PS_IPV6_5TUPLE_IP6) |
- ANA_VCAP_S1_CFG_KEY_IP4_CFG_SET(VCAP_IS1_PS_IPV4_5TUPLE_IP4) |
- ANA_VCAP_S1_CFG_KEY_OTHER_CFG_SET(VCAP_IS1_PS_OTHER_NORMAL);
- for (int p = 0; p < lan966x->num_phys_ports; ++p) {
- if (!lan966x->ports[p])
- continue;
- for (int l = 0; l < LAN966X_IS1_LOOKUPS; ++l)
- lan_wr(val, lan966x, ANA_VCAP_S1_CFG(p, l));
- lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),
- ANA_VCAP_CFG_S1_ENA, lan966x,
- ANA_VCAP_CFG(p));
- }
- break;
- case VCAP_TYPE_IS2:
- for (int p = 0; p < lan966x->num_phys_ports; ++p)
- lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p));
- break;
- case VCAP_TYPE_ES0:
- for (int p = 0; p < lan966x->num_phys_ports; ++p)
- lan_rmw(REW_PORT_CFG_ES0_EN_SET(false),
- REW_PORT_CFG_ES0_EN, lan966x,
- REW_PORT_CFG(p));
- break;
- default:
- pr_err("vcap type: %s not supported\n",
- lan966x_vcaps[admin->vtype].name);
- break;
- }
- }
- int lan966x_vcap_init(struct lan966x *lan966x)
- {
- struct lan966x_vcap_inst *cfg;
- struct vcap_control *ctrl;
- struct vcap_admin *admin;
- struct dentry *dir;
- ctrl = kzalloc_obj(*ctrl);
- if (!ctrl)
- return -ENOMEM;
- ctrl->vcaps = lan966x_vcaps;
- ctrl->stats = &lan966x_vcap_stats;
- ctrl->ops = &lan966x_vcap_ops;
- INIT_LIST_HEAD(&ctrl->list);
- for (int i = 0; i < ARRAY_SIZE(lan966x_vcap_inst_cfg); ++i) {
- cfg = &lan966x_vcap_inst_cfg[i];
- admin = lan966x_vcap_admin_alloc(lan966x, ctrl, cfg);
- if (IS_ERR(admin))
- return PTR_ERR(admin);
- lan966x_vcap_block_init(lan966x, admin, cfg);
- lan966x_vcap_port_key_deselection(lan966x, admin);
- list_add_tail(&admin->list, &ctrl->list);
- }
- dir = vcap_debugfs(lan966x->dev, lan966x->debugfs_root, ctrl);
- for (int p = 0; p < lan966x->num_phys_ports; ++p) {
- if (lan966x->ports[p]) {
- vcap_port_debugfs(lan966x->dev, dir, ctrl,
- lan966x->ports[p]->dev);
- lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(true),
- ANA_VCAP_S2_CFG_ENA, lan966x,
- ANA_VCAP_S2_CFG(lan966x->ports[p]->chip_port));
- lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),
- ANA_VCAP_CFG_S1_ENA, lan966x,
- ANA_VCAP_CFG(lan966x->ports[p]->chip_port));
- lan_rmw(REW_PORT_CFG_ES0_EN_SET(true),
- REW_PORT_CFG_ES0_EN, lan966x,
- REW_PORT_CFG(lan966x->ports[p]->chip_port));
- }
- }
- /* Statistics: Use ESDX from ES0 if hit, otherwise no counting */
- lan_rmw(REW_STAT_CFG_STAT_MODE_SET(1),
- REW_STAT_CFG_STAT_MODE, lan966x,
- REW_STAT_CFG);
- lan966x->vcap_ctrl = ctrl;
- return 0;
- }
- void lan966x_vcap_deinit(struct lan966x *lan966x)
- {
- struct vcap_admin *admin, *admin_next;
- struct vcap_control *ctrl;
- ctrl = lan966x->vcap_ctrl;
- if (!ctrl)
- return;
- list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) {
- lan966x_vcap_port_key_deselection(lan966x, admin);
- vcap_del_rules(ctrl, admin);
- list_del(&admin->list);
- lan966x_vcap_admin_free(admin);
- }
- kfree(ctrl);
- }
|