提交 c1aa0a90 编写于 作者: D David S. Miller

Merge branch 'sparx5-IS2-VCAP'

Steen Hegelund says:

====================
Add support for Sparx5 IS2 VCAP

This provides initial support for the Sparx5 VCAP functionality via the
'tc' traffic control userspace tool and its flower filter.

Overview:
=========

The supported flower filter keys and actions are:

- source and destination MAC address keys
- trap action
- pass action

The supported Sparx5 VCAPs are: IS2 (see below for more info)

The VCAP (Versatile Content-Aware Processor) feature is essentially a TCAM
with rules consisting of:

- Programmable key fields
- Programmable action fields
- A counter (which may be only one bit wide)

Besides this each VCAP has:

- A number of independent lookups
- A keyset configuration typically per port per lookup

VCAPs are used in many of the TSN features such as PSFP, PTP, FRER as well
as the general shaping, policing and access control, so it is an important
building block for these advanced features.

Functionality:
==============

When a frame is passed to a VCAP the VCAP will generate a set of keys
(keyset) based on the traffic type.  If there is a rule created with this
keyset in the VCAP and the values of the keys matches the values in the
keyset of the frame, the rule is said to match and the actions in the rule
will be executed and the rule counter will be incremented.  No more rules
will be examined in this VCAP lookup.

If there is no match in the current lookup the frame will be matched
against the next lookup (some VCAPs do the processing of the lookups in
parallel).

The Sparx5 SoC has 6 different VCAP types:

- IS0: Ingress Stage 0 (AKA CLM) mostly handles classification
- IS2: Ingress Stage 2 mostly handles access control
- IP6PFX: IPv6 prefix: Provides tables for IPV6 address management
- LPM: Longest Path Match for IP guarding and routing
- ES0: Egress Stage 0 is mostly used for CPU copying and multicast handling
- ES2: Egress Stage 2 is known as the rewriter and mostly updates tags

Design:
=======

The VCAP implementation provides switchcore independent handling of rules
and supports:

- Creating and deleting rules
- Updating and getting rules

The platform specific API implementation as well as the platform specific
model of the VCAP instances are attached to the VCAP API and a client can
then access rules via the API in a platform independent way, with the
limitations that each VCAP has in terms of is supported keys and actions.

The VCAP model is generated from information delivered by the designers of
the VCAP hardware.

Here is an illustration of this:

  +------------------+     +------------------+
  | TC flower filter |     | PTP client       |
  | for Sparx5       |     | for Sparx5       |
  +-------------\----+     +---------/--------+
                 \                  /
                  \                /
                   \              /
                    \            /
                     \          /
                 +----v--------v----+
                 |     VCAP API     |
                 +---------|--------+
                           |
                           |
                           |
                           |
                 +---------v--------+
                 |   VCAP control   |
                 |   instance       |
                 +----/--------|----+
                     /         |
                    /          |
                   /           |
                  /            |
  +--------------v---+    +----v-------------+
  |   Sparx5 VCAP    |    | Sparx5 VCAP API  |
  |   model          |    | Implementation   |
  +------------------+    +---------|--------+
                                    |
                                    |
                                    |
                                    |
                          +---------v--------+
                          | Sparx5 VCAP HW   |
                          +------------------+

Delivery:
=========

For now only the IS2 is supported but later the IS0, ES0 and ES2 will be
added. There are currently no plans to support the IP6PFX and the LPM
VCAPs.

The IS2 VCAP has 4 lookups and they are accessible with a TC chain id:

- chain 8000000: IS2 Lookup 0
- chain 8100000: IS2 Lookup 1
- chain 8200000: IS2 Lookup 2
- chain 8300000: IS2 Lookup 3

These lookups are executed in parallel by the IS2 VCAP but the actions are
executed in series (the datasheet explains what happens if actions
overlap).

The functionality of TC flower as well as TC matchall filters will be
expanded in later submissions as well as the number of VCAPs supported.

This is current plan:

- add support for more TC flower filter keys and extend the Sparx5 port
  keyset configuration
- support for TC protocol all
- debugfs support for inspecting rules
- TC flower filter statistics
- Sparx5 IS0 VCAP support and more TC keys and actions to support this
- add TC policer and drop action support (depends on the Sparx5 QoS support
  upstreamed separately)
- Sparx5 ES0 VCAP support and more TC actions to support this
- TC flower template support
- TC matchall filter support for mirroring and policing ports
- TC flower filter mirror action support
- Sparx5 ES2 VCAP support

The LAN966x switchcore will also be updated to use the VCAP API as well as
future Microchip switches.
The LAN966x has 3 VCAPS (IS1, IS2 and ES0) and a slightly different keyset
and actionset portfolio than Sparx5.

Version History:
================
v3      Moved the sparx5_tc_flower_set_exterr function to the VCAP API and
        renamed it.
        Moved the sparx5_netbytes_copy function to the VCAP_API and renamed
        it (thanks Horatiu Vultur).
        Fixed indentation in the vcap_write_rule function.
        Added a comment mentioning the typegroup table terminator in the
        vcap_iter_skip_tg function.

v2      Made the KUNIT test model a superset of the real model to fix a
        kernel robot build error.

v1      Initial version
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
......@@ -2439,6 +2439,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
T: git git://github.com/microchip-ung/linux-upstream.git
F: arch/arm64/boot/dts/microchip/
F: drivers/net/ethernet/microchip/vcap/
F: drivers/pinctrl/pinctrl-microchip-sgpio.c
N: sparx5
......
......@@ -57,5 +57,6 @@ config LAN743X
source "drivers/net/ethernet/microchip/lan966x/Kconfig"
source "drivers/net/ethernet/microchip/sparx5/Kconfig"
source "drivers/net/ethernet/microchip/vcap/Kconfig"
endif # NET_VENDOR_MICROCHIP
......@@ -11,3 +11,4 @@ lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
obj-$(CONFIG_LAN966X_SWITCH) += lan966x/
obj-$(CONFIG_SPARX5_SWITCH) += sparx5/
obj-$(CONFIG_VCAP) += vcap/
......@@ -9,5 +9,6 @@ config SPARX5_SWITCH
select PHYLINK
select PHY_SPARX5_SERDES
select RESET_CONTROLLER
select VCAP
help
This driver supports the Sparx5 network switch device.
......@@ -5,7 +5,11 @@
obj-$(CONFIG_SPARX5_SWITCH) += sparx5-switch.o
sparx5-switch-objs := sparx5_main.o sparx5_packet.o \
sparx5-switch-y := sparx5_main.o sparx5_packet.o \
sparx5_netdev.o sparx5_phylink.o sparx5_port.o sparx5_mactable.o sparx5_vlan.o \
sparx5_switchdev.o sparx5_calendar.o sparx5_ethtool.o sparx5_fdma.o \
sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o
sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \
sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o
# Provide include files
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap
......@@ -672,6 +672,14 @@ static int sparx5_start(struct sparx5 *sparx5)
sparx5_board_init(sparx5);
err = sparx5_register_notifier_blocks(sparx5);
if (err)
return err;
err = sparx5_vcap_init(sparx5);
if (err) {
sparx5_unregister_notifier_blocks(sparx5);
return err;
}
/* Start Frame DMA with fallback to register based INJ/XTR */
err = -ENXIO;
......@@ -906,6 +914,7 @@ static int mchp_sparx5_remove(struct platform_device *pdev)
sparx5_ptp_deinit(sparx5);
sparx5_fdma_stop(sparx5);
sparx5_cleanup_ports(sparx5);
sparx5_vcap_destroy(sparx5);
/* Unregister netdevs */
sparx5_unregister_notifier_blocks(sparx5);
......
......@@ -288,6 +288,8 @@ struct sparx5 {
struct mutex ptp_lock; /* lock for ptp interface state */
u16 ptp_skbs;
int ptp_irq;
/* VCAP */
struct vcap_control *vcap_ctrl;
/* PGID allocation map */
u8 pgid_map[PGID_TABLE_SIZE];
};
......@@ -382,6 +384,10 @@ void sparx5_ptp_txtstamp_release(struct sparx5_port *port,
struct sk_buff *skb);
irqreturn_t sparx5_ptp_irq_handler(int irq, void *args);
/* sparx5_vcap_impl.c */
int sparx5_vcap_init(struct sparx5 *sparx5);
void sparx5_vcap_destroy(struct sparx5 *sparx5);
/* sparx5_pgid.c */
enum sparx5_pgid_type {
SPX5_PGID_FREE,
......
......@@ -10,6 +10,50 @@
#include "sparx5_main.h"
#include "sparx5_qos.h"
/* tc block handling */
static LIST_HEAD(sparx5_block_cb_list);
static int sparx5_tc_block_cb(enum tc_setup_type type,
void *type_data,
void *cb_priv, bool ingress)
{
struct net_device *ndev = cb_priv;
if (type == TC_SETUP_CLSFLOWER)
return sparx5_tc_flower(ndev, type_data, ingress);
return -EOPNOTSUPP;
}
static int sparx5_tc_block_cb_ingress(enum tc_setup_type type,
void *type_data,
void *cb_priv)
{
return sparx5_tc_block_cb(type, type_data, cb_priv, true);
}
static int sparx5_tc_block_cb_egress(enum tc_setup_type type,
void *type_data,
void *cb_priv)
{
return sparx5_tc_block_cb(type, type_data, cb_priv, false);
}
static int sparx5_tc_setup_block(struct net_device *ndev,
struct flow_block_offload *fbo)
{
flow_setup_cb_t *cb;
if (fbo->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
cb = sparx5_tc_block_cb_ingress;
else if (fbo->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
cb = sparx5_tc_block_cb_egress;
else
return -EOPNOTSUPP;
return flow_block_cb_setup_simple(fbo, &sparx5_block_cb_list,
cb, ndev, ndev, false);
}
static void sparx5_tc_get_layer_and_idx(u32 parent, u32 portno, u32 *layer,
u32 *idx)
{
......@@ -111,6 +155,8 @@ int sparx5_port_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data)
{
switch (type) {
case TC_SETUP_BLOCK:
return sparx5_tc_setup_block(ndev, type_data);
case TC_SETUP_QDISC_MQPRIO:
return sparx5_tc_setup_qdisc_mqprio(ndev, type_data);
case TC_SETUP_QDISC_TBF:
......
......@@ -7,9 +7,23 @@
#ifndef __SPARX5_TC_H__
#define __SPARX5_TC_H__
#include <net/flow_offload.h>
#include <linux/netdevice.h>
/* Controls how PORT_MASK is applied */
enum SPX5_PORT_MASK_MODE {
SPX5_PMM_OR_DSTMASK,
SPX5_PMM_AND_VLANMASK,
SPX5_PMM_REPLACE_PGID,
SPX5_PMM_REPLACE_ALL,
SPX5_PMM_REDIR_PGID,
SPX5_PMM_OR_PGID_MASK,
};
int sparx5_port_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data);
int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
bool ingress);
#endif /* __SPARX5_TC_H__ */
// SPDX-License-Identifier: GPL-2.0+
/* Microchip VCAP API
*
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
*/
#include <net/tcp.h>
#include "sparx5_tc.h"
#include "vcap_api.h"
#include "vcap_api_client.h"
#include "sparx5_main.h"
#include "sparx5_vcap_impl.h"
struct sparx5_tc_flower_parse_usage {
struct flow_cls_offload *fco;
struct flow_rule *frule;
struct vcap_rule *vrule;
unsigned int used_keys;
};
static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_usage *st)
{
enum vcap_key_field smac_key = VCAP_KF_L2_SMAC;
enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC;
struct flow_match_eth_addrs match;
struct vcap_u48_key smac, dmac;
int err = 0;
flow_rule_match_eth_addrs(st->frule, &match);
if (!is_zero_ether_addr(match.mask->src)) {
vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN);
vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN);
err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac);
if (err)
goto out;
}
if (!is_zero_ether_addr(match.mask->dst)) {
vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN);
vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN);
err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac);
if (err)
goto out;
}
st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS);
return err;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error");
return err;
}
static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_usage *st) = {
/* More dissector handlers will be added here later */
[FLOW_DISSECTOR_KEY_ETH_ADDRS] = sparx5_tc_flower_handler_ethaddr_usage,
};
static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
struct vcap_admin *admin,
struct vcap_rule *vrule)
{
struct sparx5_tc_flower_parse_usage state = {
.fco = fco,
.vrule = vrule,
};
int idx, err = 0;
state.frule = flow_cls_offload_flow_rule(fco);
for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
if (!flow_rule_match_key(state.frule, idx))
continue;
if (!sparx5_tc_flower_usage_handlers[idx])
continue;
err = sparx5_tc_flower_usage_handlers[idx](&state);
if (err)
return err;
}
return err;
}
static int sparx5_tc_flower_replace(struct net_device *ndev,
struct flow_cls_offload *fco,
struct vcap_admin *admin)
{
struct sparx5_port *port = netdev_priv(ndev);
struct flow_action_entry *act;
struct vcap_control *vctrl;
struct flow_rule *frule;
struct vcap_rule *vrule;
int err, idx;
frule = flow_cls_offload_flow_rule(fco);
if (!flow_action_has_entries(&frule->action)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
return -EINVAL;
}
if (!flow_action_basic_hw_stats_check(&frule->action, fco->common.extack))
return -EOPNOTSUPP;
vctrl = port->sparx5->vcap_ctrl;
vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
fco->common.prio, 0);
if (IS_ERR(vrule))
return PTR_ERR(vrule);
vrule->cookie = fco->cookie;
sparx5_tc_use_dissectors(fco, admin, vrule);
flow_action_for_each(idx, act, &frule->action) {
switch (act->id) {
case FLOW_ACTION_TRAP:
err = vcap_rule_add_action_bit(vrule,
VCAP_AF_CPU_COPY_ENA,
VCAP_BIT_1);
if (err)
goto out;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_CPU_QUEUE_NUM, 0);
if (err)
goto out;
err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE,
SPX5_PMM_REPLACE_ALL);
if (err)
goto out;
/* For now the actionset is hardcoded */
err = vcap_set_rule_set_actionset(vrule,
VCAP_AFS_BASE_TYPE);
if (err)
goto out;
break;
case FLOW_ACTION_ACCEPT:
/* For now the actionset is hardcoded */
err = vcap_set_rule_set_actionset(vrule,
VCAP_AFS_BASE_TYPE);
if (err)
goto out;
break;
default:
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Unsupported TC action");
err = -EOPNOTSUPP;
goto out;
}
}
/* For now the keyset is hardcoded */
err = vcap_set_rule_set_keyset(vrule, VCAP_KFS_MAC_ETYPE);
if (err) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"No matching port keyset for filter protocol and keys");
goto out;
}
err = vcap_val_rule(vrule, ETH_P_ALL);
if (err) {
vcap_set_tc_exterr(fco, vrule);
goto out;
}
err = vcap_add_rule(vrule);
if (err)
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Could not add the filter");
out:
vcap_free_rule(vrule);
return err;
}
static int sparx5_tc_flower_destroy(struct net_device *ndev,
struct flow_cls_offload *fco,
struct vcap_admin *admin)
{
struct sparx5_port *port = netdev_priv(ndev);
struct vcap_control *vctrl;
int err = -ENOENT, rule_id;
vctrl = port->sparx5->vcap_ctrl;
while (true) {
rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
if (rule_id <= 0)
break;
err = vcap_del_rule(vctrl, ndev, rule_id);
if (err) {
pr_err("%s:%d: could not delete rule %d\n",
__func__, __LINE__, rule_id);
break;
}
}
return err;
}
int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
bool ingress)
{
struct sparx5_port *port = netdev_priv(ndev);
struct vcap_control *vctrl;
struct vcap_admin *admin;
int err = -EINVAL;
/* Get vcap instance from the chain id */
vctrl = port->sparx5->vcap_ctrl;
admin = vcap_find_admin(vctrl, fco->common.chain_index);
if (!admin) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
return err;
}
switch (fco->command) {
case FLOW_CLS_REPLACE:
return sparx5_tc_flower_replace(ndev, fco, admin);
case FLOW_CLS_DESTROY:
return sparx5_tc_flower_destroy(ndev, fco, admin);
default:
return -EOPNOTSUPP;
}
}
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
/* This file is autogenerated by cml-utils 2022-10-13 10:04:41 +0200.
* Commit ID: fd7cafd175899f0672c73afb3a30fc872500ae86
*/
#ifndef __SPARX5_VCAP_AG_API_H__
#define __SPARX5_VCAP_AG_API_H__
/* VCAPs */
extern const struct vcap_info sparx5_vcaps[];
extern const struct vcap_statistics sparx5_vcap_stats;
#endif /* __SPARX5_VCAP_AG_API_H__ */
// SPDX-License-Identifier: GPL-2.0+
/* Microchip Sparx5 Switch driver VCAP implementation
*
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
*
* The Sparx5 Chip Register Model can be browsed at this location:
* https://github.com/microchip-ung/sparx-5_reginfo
*/
#include <linux/types.h>
#include <linux/list.h>
#include "vcap_api.h"
#include "vcap_api_client.h"
#include "sparx5_main_regs.h"
#include "sparx5_main.h"
#include "sparx5_vcap_impl.h"
#include "sparx5_vcap_ag_api.h"
#define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */
#define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */
#define SPARX5_IS2_LOOKUPS 4
/* IS2 port keyset selection control */
/* IS2 non-ethernet traffic type keyset generation */
enum vcap_is2_port_sel_noneth {
VCAP_IS2_PS_NONETH_MAC_ETYPE,
VCAP_IS2_PS_NONETH_CUSTOM_1,
VCAP_IS2_PS_NONETH_CUSTOM_2,
VCAP_IS2_PS_NONETH_NO_LOOKUP
};
/* IS2 IPv4 unicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv4_uc {
VCAP_IS2_PS_IPV4_UC_MAC_ETYPE,
VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER,
VCAP_IS2_PS_IPV4_UC_IP_7TUPLE,
};
/* IS2 IPv4 multicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv4_mc {
VCAP_IS2_PS_IPV4_MC_MAC_ETYPE,
VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER,
VCAP_IS2_PS_IPV4_MC_IP_7TUPLE,
VCAP_IS2_PS_IPV4_MC_IP4_VID,
};
/* IS2 IPv6 unicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv6_uc {
VCAP_IS2_PS_IPV6_UC_MAC_ETYPE,
VCAP_IS2_PS_IPV6_UC_IP_7TUPLE,
VCAP_IS2_PS_IPV6_UC_IP6_STD,
VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER,
};
/* IS2 IPv6 multicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv6_mc {
VCAP_IS2_PS_IPV6_MC_MAC_ETYPE,
VCAP_IS2_PS_IPV6_MC_IP_7TUPLE,
VCAP_IS2_PS_IPV6_MC_IP6_VID,
VCAP_IS2_PS_IPV6_MC_IP6_STD,
VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER,
};
/* IS2 ARP traffic type keyset generation */
enum vcap_is2_port_sel_arp {
VCAP_IS2_PS_ARP_MAC_ETYPE,
VCAP_IS2_PS_ARP_ARP,
};
static struct sparx5_vcap_inst {
enum vcap_type vtype; /* type of vcap */
int vinst; /* instance number within the same type */
int lookups; /* number of lookups in this vcap type */
int lookups_per_instance; /* number of lookups in this instance */
int first_cid; /* first chain id in this vcap */
int last_cid; /* last chain id in this vcap */
int count; /* number of available addresses, not in super vcap */
int map_id; /* id in the super vcap block mapping (if applicable) */
int blockno; /* starting block in super vcap (if applicable) */
int blocks; /* number of blocks in super vcap (if applicable) */
} sparx5_vcap_inst_cfg[] = {
{
.vtype = VCAP_TYPE_IS2, /* IS2-0 */
.vinst = 0,
.map_id = 4,
.lookups = SPARX5_IS2_LOOKUPS,
.lookups_per_instance = SPARX5_IS2_LOOKUPS / 2,
.first_cid = SPARX5_VCAP_CID_IS2_L0,
.last_cid = SPARX5_VCAP_CID_IS2_L2 - 1,
.blockno = 0, /* Maps block 0-1 */
.blocks = 2,
},
{
.vtype = VCAP_TYPE_IS2, /* IS2-1 */
.vinst = 1,
.map_id = 5,
.lookups = SPARX5_IS2_LOOKUPS,
.lookups_per_instance = SPARX5_IS2_LOOKUPS / 2,
.first_cid = SPARX5_VCAP_CID_IS2_L2,
.last_cid = SPARX5_VCAP_CID_IS2_MAX,
.blockno = 2, /* Maps block 2-3 */
.blocks = 2,
},
};
/* Await the super VCAP completion of the current operation */
static void sparx5_vcap_wait_super_update(struct sparx5 *sparx5)
{
u32 value;
read_poll_timeout(spx5_rd, value,
!VCAP_SUPER_CTRL_UPDATE_SHOT_GET(value), 500, 10000,
false, sparx5, VCAP_SUPER_CTRL);
}
/* Initializing a VCAP address range: only IS2 for now */
static void _sparx5_vcap_range_init(struct sparx5 *sparx5,
struct vcap_admin *admin,
u32 addr, u32 count)
{
u32 size = count - 1;
spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) |
VCAP_SUPER_CFG_MV_SIZE_SET(size),
sparx5, VCAP_SUPER_CFG);
spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |
VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) |
VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) |
VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) |
VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) |
VCAP_SUPER_CTRL_CLEAR_CACHE_SET(true) |
VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true),
sparx5, VCAP_SUPER_CTRL);
sparx5_vcap_wait_super_update(sparx5);
}
/* Initializing VCAP rule data area */
static void sparx5_vcap_block_init(struct sparx5 *sparx5,
struct vcap_admin *admin)
{
_sparx5_vcap_range_init(sparx5, admin, admin->first_valid_addr,
admin->last_valid_addr -
admin->first_valid_addr);
}
/* Get the keyset name from the sparx5 VCAP model */
static const char *sparx5_vcap_keyset_name(struct net_device *ndev,
enum vcap_keyfield_set keyset)
{
struct sparx5_port *port = netdev_priv(ndev);
return port->sparx5->vcap_ctrl->stats->keyfield_set_names[keyset];
}
/* Check if this is the first lookup of IS2 */
static bool sparx5_vcap_is2_is_first_chain(struct vcap_rule *rule)
{
return (rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L0 &&
rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L1) ||
((rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L2 &&
rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L3));
}
/* Set the narrow range ingress port mask on a rule */
static void sparx5_vcap_add_range_port_mask(struct vcap_rule *rule,
struct net_device *ndev)
{
struct sparx5_port *port = netdev_priv(ndev);
u32 port_mask;
u32 range;
range = port->portno / BITS_PER_TYPE(u32);
/* Port bit set to match-any */
port_mask = ~BIT(port->portno % BITS_PER_TYPE(u32));
vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_SEL, 0, 0xf);
vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_RNG, range, 0xf);
vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0, port_mask);
}
/* Set the wide range ingress port mask on a rule */
static void sparx5_vcap_add_wide_port_mask(struct vcap_rule *rule,
struct net_device *ndev)
{
struct sparx5_port *port = netdev_priv(ndev);
struct vcap_u72_key port_mask;
u32 range;
/* Port bit set to match-any */
memset(port_mask.value, 0, sizeof(port_mask.value));
memset(port_mask.mask, 0xff, sizeof(port_mask.mask));
range = port->portno / BITS_PER_BYTE;
port_mask.mask[range] = ~BIT(port->portno % BITS_PER_BYTE);
vcap_rule_add_key_u72(rule, VCAP_KF_IF_IGR_PORT_MASK, &port_mask);
}
/* API callback used for validating a field keyset (check the port keysets) */
static enum vcap_keyfield_set
sparx5_vcap_validate_keyset(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_rule *rule,
struct vcap_keyset_list *kslist,
u16 l3_proto)
{
if (!kslist || kslist->cnt == 0)
return VCAP_KFS_NO_VALUE;
/* for now just return whatever the API suggests */
return kslist->keysets[0];
}
/* API callback used for adding default fields to a rule */
static void sparx5_vcap_add_default_fields(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_rule *rule)
{
const struct vcap_field *field;
field = vcap_lookup_keyfield(rule, VCAP_KF_IF_IGR_PORT_MASK);
if (field && field->width == SPX5_PORTS)
sparx5_vcap_add_wide_port_mask(rule, ndev);
else if (field && field->width == BITS_PER_TYPE(u32))
sparx5_vcap_add_range_port_mask(rule, ndev);
else
pr_err("%s:%d: %s: could not add an ingress port mask for: %s\n",
__func__, __LINE__, netdev_name(ndev),
sparx5_vcap_keyset_name(ndev, rule->keyset));
/* add the lookup bit */
if (sparx5_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);
}
/* API callback used for erasing the vcap cache area (not the register area) */
static void sparx5_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));
}
/* API callback used for writing to the VCAP cache */
static void sparx5_vcap_cache_write(struct net_device *ndev,
struct vcap_admin *admin,
enum vcap_selection sel,
u32 start,
u32 count)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5 = port->sparx5;
u32 *keystr, *mskstr, *actstr;
int idx;
keystr = &admin->cache.keystream[start];
mskstr = &admin->cache.maskstream[start];
actstr = &admin->cache.actionstream[start];
switch (sel) {
case VCAP_SEL_ENTRY:
for (idx = 0; idx < count; ++idx) {
/* Avoid 'match-off' by setting value & mask */
spx5_wr(keystr[idx] & mskstr[idx], sparx5,
VCAP_SUPER_VCAP_ENTRY_DAT(idx));
spx5_wr(~mskstr[idx], sparx5,
VCAP_SUPER_VCAP_MASK_DAT(idx));
}
break;
case VCAP_SEL_ACTION:
for (idx = 0; idx < count; ++idx)
spx5_wr(actstr[idx], sparx5,
VCAP_SUPER_VCAP_ACTION_DAT(idx));
break;
case VCAP_SEL_ALL:
pr_err("%s:%d: cannot write all streams at once\n",
__func__, __LINE__);
break;
default:
break;
}
}
/* API callback used for reading from the VCAP into the VCAP cache */
static void sparx5_vcap_cache_read(struct net_device *ndev,
struct vcap_admin *admin,
enum vcap_selection sel, u32 start,
u32 count)
{
/* this will be added later */
}
/* API callback used for initializing a VCAP address range */
static void sparx5_vcap_range_init(struct net_device *ndev,
struct vcap_admin *admin, u32 addr,
u32 count)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5 = port->sparx5;
_sparx5_vcap_range_init(sparx5, admin, addr, count);
}
/* API callback used for updating the VCAP cache */
static void sparx5_vcap_update(struct net_device *ndev,
struct vcap_admin *admin, enum vcap_command cmd,
enum vcap_selection sel, u32 addr)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5 = port->sparx5;
bool clear;
clear = (cmd == VCAP_CMD_INITIALIZE);
spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) |
VCAP_SUPER_CFG_MV_SIZE_SET(0), sparx5, VCAP_SUPER_CFG);
spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) |
VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |
VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |
VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |
VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) |
VCAP_SUPER_CTRL_CLEAR_CACHE_SET(clear) |
VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true),
sparx5, VCAP_SUPER_CTRL);
sparx5_vcap_wait_super_update(sparx5);
}
/* API callback used for moving a block of rules in the VCAP */
static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin,
u32 addr, int offset, int count)
{
/* this will be added later */
}
/* Provide port information via a callback interface */
static int sparx5_port_info(struct net_device *ndev, enum vcap_type vtype,
int (*pf)(void *out, int arg, const char *fmt, ...),
void *out, int arg)
{
/* this will be added later */
return 0;
}
/* API callback operations: only IS2 is supported for now */
static struct vcap_operations sparx5_vcap_ops = {
.validate_keyset = sparx5_vcap_validate_keyset,
.add_default_fields = sparx5_vcap_add_default_fields,
.cache_erase = sparx5_vcap_cache_erase,
.cache_write = sparx5_vcap_cache_write,
.cache_read = sparx5_vcap_cache_read,
.init = sparx5_vcap_range_init,
.update = sparx5_vcap_update,
.move = sparx5_vcap_move,
.port_info = sparx5_port_info,
};
/* Enable lookups per port and set the keyset generation: only IS2 for now */
static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5,
struct vcap_admin *admin)
{
int portno, lookup;
u32 keysel;
/* enable all 4 lookups on all ports */
for (portno = 0; portno < SPX5_PORTS; ++portno)
spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5,
ANA_ACL_VCAP_S2_CFG(portno));
/* all traffic types generate the MAC_ETYPE keyset for now in all
* lookups on all ports
*/
keysel = ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(true) |
ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(VCAP_IS2_PS_NONETH_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_MC_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_UC_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_MC_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_UC_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(VCAP_IS2_PS_ARP_MAC_ETYPE);
for (lookup = 0; lookup < admin->lookups; ++lookup) {
for (portno = 0; portno < SPX5_PORTS; ++portno) {
spx5_wr(keysel, sparx5,
ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));
}
}
}
/* Disable lookups per port and set the keyset generation: only IS2 for now */
static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5,
struct vcap_admin *admin)
{
int portno;
for (portno = 0; portno < SPX5_PORTS; ++portno)
spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0),
ANA_ACL_VCAP_S2_CFG_SEC_ENA,
sparx5,
ANA_ACL_VCAP_S2_CFG(portno));
}
static void sparx5_vcap_admin_free(struct vcap_admin *admin)
{
if (!admin)
return;
kfree(admin->cache.keystream);
kfree(admin->cache.maskstream);
kfree(admin->cache.actionstream);
kfree(admin);
}
/* Allocate a vcap instance with a rule list and a cache area */
static struct vcap_admin *
sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl,
const struct sparx5_vcap_inst *cfg)
{
struct vcap_admin *admin;
admin = kzalloc(sizeof(*admin), GFP_KERNEL);
if (!admin)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&admin->list);
INIT_LIST_HEAD(&admin->rules);
admin->vtype = cfg->vtype;
admin->vinst = cfg->vinst;
admin->lookups = cfg->lookups;
admin->lookups_per_instance = cfg->lookups_per_instance;
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) {
sparx5_vcap_admin_free(admin);
return ERR_PTR(-ENOMEM);
}
return admin;
}
/* Do block allocations and provide addresses for VCAP instances */
static void sparx5_vcap_block_alloc(struct sparx5 *sparx5,
struct vcap_admin *admin,
const struct sparx5_vcap_inst *cfg)
{
int idx;
/* Super VCAP block mapping and address configuration. Block 0
* is assigned addresses 0 through 3071, block 1 is assigned
* addresses 3072 though 6143, and so on.
*/
for (idx = cfg->blockno; idx < cfg->blockno + cfg->blocks; ++idx) {
spx5_wr(VCAP_SUPER_IDX_CORE_IDX_SET(idx), sparx5,
VCAP_SUPER_IDX);
spx5_wr(VCAP_SUPER_MAP_CORE_MAP_SET(cfg->map_id), sparx5,
VCAP_SUPER_MAP);
}
admin->first_valid_addr = cfg->blockno * SUPER_VCAP_BLK_SIZE;
admin->last_used_addr = admin->first_valid_addr +
cfg->blocks * SUPER_VCAP_BLK_SIZE;
admin->last_valid_addr = admin->last_used_addr - 1;
}
/* Allocate a vcap control and vcap instances and configure the system */
int sparx5_vcap_init(struct sparx5 *sparx5)
{
const struct sparx5_vcap_inst *cfg;
struct vcap_control *ctrl;
struct vcap_admin *admin;
int err = 0, idx;
/* Create a VCAP control instance that owns the platform specific VCAP
* model with VCAP instances and information about keysets, keys,
* actionsets and actions
* - Create administrative state for each available VCAP
* - Lists of rules
* - Address information
* - Initialize VCAP blocks
* - Configure port keysets
*/
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return -ENOMEM;
sparx5->vcap_ctrl = ctrl;
/* select the sparx5 VCAP model */
ctrl->vcaps = sparx5_vcaps;
ctrl->stats = &sparx5_vcap_stats;
/* Setup callbacks to allow the API to use the VCAP HW */
ctrl->ops = &sparx5_vcap_ops;
INIT_LIST_HEAD(&ctrl->list);
for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) {
cfg = &sparx5_vcap_inst_cfg[idx];
admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg);
if (IS_ERR(admin)) {
err = PTR_ERR(admin);
pr_err("%s:%d: vcap allocation failed: %d\n",
__func__, __LINE__, err);
return err;
}
sparx5_vcap_block_alloc(sparx5, admin, cfg);
sparx5_vcap_block_init(sparx5, admin);
if (cfg->vinst == 0)
sparx5_vcap_port_key_selection(sparx5, admin);
list_add_tail(&admin->list, &ctrl->list);
}
return err;
}
void sparx5_vcap_destroy(struct sparx5 *sparx5)
{
struct vcap_control *ctrl = sparx5->vcap_ctrl;
struct vcap_admin *admin, *admin_next;
if (!ctrl)
return;
list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) {
sparx5_vcap_port_key_deselection(sparx5, admin);
vcap_del_rules(ctrl, admin);
list_del(&admin->list);
sparx5_vcap_admin_free(admin);
}
kfree(ctrl);
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Microchip Sparx5 Switch driver VCAP implementation
*
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
*
* The Sparx5 Chip Register Model can be browsed at this location:
* https://github.com/microchip-ung/sparx-5_reginfo
*/
#ifndef __SPARX5_VCAP_IMPL_H__
#define __SPARX5_VCAP_IMPL_H__
#define SPARX5_VCAP_CID_IS2_L0 VCAP_CID_INGRESS_STAGE2_L0 /* IS2 lookup 0 */
#define SPARX5_VCAP_CID_IS2_L1 VCAP_CID_INGRESS_STAGE2_L1 /* IS2 lookup 1 */
#define SPARX5_VCAP_CID_IS2_L2 VCAP_CID_INGRESS_STAGE2_L2 /* IS2 lookup 2 */
#define SPARX5_VCAP_CID_IS2_L3 VCAP_CID_INGRESS_STAGE2_L3 /* IS2 lookup 3 */
#define SPARX5_VCAP_CID_IS2_MAX \
(VCAP_CID_INGRESS_STAGE2_L3 + VCAP_CID_LOOKUP_SIZE - 1) /* IS2 Max */
#endif /* __SPARX5_VCAP_IMPL_H__ */
# SPDX-License-Identifier: GPL-2.0-only
#
# Microchip VCAP API configuration
#
if NET_VENDOR_MICROCHIP
config VCAP
bool "VCAP (Versatile Content-Aware Processor) library"
help
Provides the basic VCAP functionality for multiple Microchip switchcores
A VCAP is essentially a TCAM with rules consisting of
- Programmable key fields
- Programmable action fields
- A counter (which may be only one bit wide)
Besides this each VCAP has:
- A number of lookups
- A keyset configuration per port per lookup
The VCAP implementation provides switchcore independent handling of rules
and supports:
- Creating and deleting rules
- Updating and getting rules
The platform specific configuration as well as the platform specific model
of the VCAP instances are attached to the VCAP API and a client can then
access rules via the API in a platform independent way, with the
limitations that each VCAP has in terms of its supported keys and actions.
Different switchcores will have different VCAP instances with different
characteristics. Look in the datasheet for the VCAP specifications for the
specific switchcore.
config VCAP_KUNIT_TEST
bool "KUnit test for VCAP library" if !KUNIT_ALL_TESTS
depends on KUNIT
depends on KUNIT=y && VCAP=y && y
default KUNIT_ALL_TESTS
help
This builds unit tests for the VCAP library.
For more information on KUnit and unit tests in general, please refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
If unsure, say N.
endif # NET_VENDOR_MICROCHIP
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the Microchip VCAP API
#
obj-$(CONFIG_VCAP) += vcap.o
obj-$(CONFIG_VCAP_KUNIT_TEST) += vcap_model_kunit.o
vcap-y += vcap_api.o
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
/* This file is autogenerated by cml-utils 2022-10-13 10:04:41 +0200.
* Commit ID: fd7cafd175899f0672c73afb3a30fc872500ae86
*/
#ifndef __VCAP_AG_API__
#define __VCAP_AG_API__
enum vcap_type {
VCAP_TYPE_IS2,
VCAP_TYPE_MAX
};
/* Keyfieldset names with origin information */
enum vcap_keyfield_set {
VCAP_KFS_NO_VALUE, /* initial value */
VCAP_KFS_ARP, /* sparx5 is2 X6 */
VCAP_KFS_IP4_OTHER, /* sparx5 is2 X6 */
VCAP_KFS_IP4_TCP_UDP, /* sparx5 is2 X6 */
VCAP_KFS_IP6_STD, /* sparx5 is2 X6 */
VCAP_KFS_IP_7TUPLE, /* sparx5 is2 X12 */
VCAP_KFS_MAC_ETYPE, /* sparx5 is2 X6 */
};
/* List of keyfields with description
*
* Keys ending in _IS are booleans derived from frame data
* Keys ending in _CLS are classified frame data
*
* VCAP_KF_8021Q_DEI_CLS: W1, sparx5: is2
* Classified DEI
* VCAP_KF_8021Q_PCP_CLS: W3, sparx5: is2
* Classified PCP
* VCAP_KF_8021Q_VID_CLS: W13, sparx5: is2
* Classified VID
* VCAP_KF_8021Q_VLAN_TAGGED_IS: W1, sparx5: is2
* Sparx5: Set if frame was received with a VLAN tag, LAN966x: Set if frame has
* one or more Q-tags. Independent of port VLAN awareness
* VCAP_KF_ARP_ADDR_SPACE_OK_IS: W1, sparx5: is2
* Set if hardware address is Ethernet
* VCAP_KF_ARP_LEN_OK_IS: W1, sparx5: is2
* Set if hardware address length = 6 (Ethernet) and IP address length = 4 (IP).
* VCAP_KF_ARP_OPCODE: W2, sparx5: is2
* ARP opcode
* VCAP_KF_ARP_OPCODE_UNKNOWN_IS: W1, sparx5: is2
* Set if not one of the codes defined in VCAP_KF_ARP_OPCODE
* VCAP_KF_ARP_PROTO_SPACE_OK_IS: W1, sparx5: is2
* Set if protocol address space is 0x0800
* VCAP_KF_ARP_SENDER_MATCH_IS: W1, sparx5: is2
* Sender Hardware Address = SMAC (ARP)
* VCAP_KF_ARP_TGT_MATCH_IS: W1, sparx5: is2
* Target Hardware Address = SMAC (RARP)
* VCAP_KF_ETYPE: W16, sparx5: is2
* Ethernet type
* VCAP_KF_ETYPE_LEN_IS: W1, sparx5: is2
* Set if frame has EtherType >= 0x600
* VCAP_KF_IF_IGR_PORT_MASK: sparx5 is2 W32, sparx5 is2 W65
* Ingress port mask, one bit per port/erleg
* VCAP_KF_IF_IGR_PORT_MASK_L3: W1, sparx5: is2
* If set, IF_IGR_PORT_MASK, IF_IGR_PORT_MASK_RNG, and IF_IGR_PORT_MASK_SEL are
* used to specify L3 interfaces
* VCAP_KF_IF_IGR_PORT_MASK_RNG: W4, sparx5: is2
* Range selector for IF_IGR_PORT_MASK. Specifies which group of 32 ports are
* available in IF_IGR_PORT_MASK
* VCAP_KF_IF_IGR_PORT_MASK_SEL: W2, sparx5: is2
* Mode selector for IF_IGR_PORT_MASK, applicable when IF_IGR_PORT_MASK_L3 == 0.
* Mapping: 0: DEFAULT 1: LOOPBACK 2: MASQUERADE 3: CPU_VD
* VCAP_KF_IP4_IS: W1, sparx5: is2
* Set if frame has EtherType = 0x800 and IP version = 4
* VCAP_KF_ISDX_CLS: W12, sparx5: is2
* Classified ISDX
* VCAP_KF_ISDX_GT0_IS: W1, sparx5: is2
* Set if classified ISDX > 0
* VCAP_KF_L2_BC_IS: W1, sparx5: is2
* Set if frame’s destination MAC address is the broadcast address
* (FF-FF-FF-FF-FF-FF).
* VCAP_KF_L2_DMAC: W48, sparx5: is2
* Destination MAC address
* VCAP_KF_L2_FWD_IS: W1, sparx5: is2
* Set if the frame is allowed to be forwarded to front ports
* VCAP_KF_L2_MC_IS: W1, sparx5: is2
* Set if frame’s destination MAC address is a multicast address (bit 40 = 1).
* VCAP_KF_L2_PAYLOAD_ETYPE: W64, sparx5: is2
* Byte 0-7 of L2 payload after Type/Len field and overloading for OAM
* VCAP_KF_L2_SMAC: W48, sparx5: is2
* Source MAC address
* VCAP_KF_L3_DIP_EQ_SIP_IS: W1, sparx5: is2
* Set if Src IP matches Dst IP address
* VCAP_KF_L3_DST_IS: W1, sparx5: is2
* Set if lookup is done for egress router leg
* VCAP_KF_L3_FRAGMENT_TYPE: W2, sparx5: is2
* L3 Fragmentation type (none, initial, suspicious, valid follow up)
* VCAP_KF_L3_FRAG_INVLD_L4_LEN: W1, sparx5: is2
* Set if frame's L4 length is less than ANA_CL:COMMON:CLM_FRAGMENT_CFG.L4_MIN_L
* EN
* VCAP_KF_L3_IP4_DIP: W32, sparx5: is2
* Destination IPv4 Address
* VCAP_KF_L3_IP4_SIP: W32, sparx5: is2
* Source IPv4 Address
* VCAP_KF_L3_IP6_DIP: W128, sparx5: is2
* Sparx5: Full IPv6 DIP, LAN966x: Either Full IPv6 DIP or a subset depending on
* frame type
* VCAP_KF_L3_IP6_SIP: W128, sparx5: is2
* Sparx5: Full IPv6 SIP, LAN966x: Either Full IPv6 SIP or a subset depending on
* frame type
* VCAP_KF_L3_IP_PROTO: W8, sparx5: is2
* IPv4 frames: IP protocol. IPv6 frames: Next header, same as for IPV4
* VCAP_KF_L3_OPTIONS_IS: W1, sparx5: is2
* Set if IPv4 frame contains options (IP len > 5)
* VCAP_KF_L3_PAYLOAD: sparx5 is2 W96, sparx5 is2 W40
* Sparx5: Payload bytes after IP header. IPv4: IPv4 options are not parsed so
* payload is always taken 20 bytes after the start of the IPv4 header, LAN966x:
* Bytes 0-6 after IP header
* VCAP_KF_L3_RT_IS: W1, sparx5: is2
* Set if frame has hit a router leg
* VCAP_KF_L3_TOS: W8, sparx5: is2
* Sparx5: Frame's IPv4/IPv6 DSCP and ECN fields, LAN966x: IP TOS field
* VCAP_KF_L3_TTL_GT0: W1, sparx5: is2
* Set if IPv4 TTL / IPv6 hop limit is greater than 0
* VCAP_KF_L4_ACK: W1, sparx5: is2
* Sparx5 and LAN966x: TCP flag ACK, LAN966x only: PTP over UDP: flagField bit 2
* (unicastFlag)
* VCAP_KF_L4_DPORT: W16, sparx5: is2
* Sparx5: TCP/UDP destination port. Overloading for IP_7TUPLE: Non-TCP/UDP IP
* frames: L4_DPORT = L3_IP_PROTO, LAN966x: TCP/UDP destination port
* VCAP_KF_L4_FIN: W1, sparx5: is2
* TCP flag FIN, LAN966x: TCP flag FIN, and for PTP over UDP: messageType bit 1
* VCAP_KF_L4_PAYLOAD: W64, sparx5: is2
* Payload bytes after TCP/UDP header Overloading for IP_7TUPLE: Non TCP/UDP
* frames: Payload bytes 0–7 after IP header. IPv4 options are not parsed so
* payload is always taken 20 bytes after the start of the IPv4 header for non
* TCP/UDP IPv4 frames
* VCAP_KF_L4_PSH: W1, sparx5: is2
* Sparx5: TCP flag PSH, LAN966x: TCP: TCP flag PSH. PTP over UDP: flagField bit
* 1 (twoStepFlag)
* VCAP_KF_L4_RNG: W16, sparx5: is2
* Range checker bitmask (one for each range checker). Input into range checkers
* is taken from classified results (VID, DSCP) and frame (SPORT, DPORT, ETYPE,
* outer VID, inner VID)
* VCAP_KF_L4_RST: W1, sparx5: is2
* Sparx5: TCP flag RST , LAN966x: TCP: TCP flag RST. PTP over UDP: messageType
* bit 3
* VCAP_KF_L4_SEQUENCE_EQ0_IS: W1, sparx5: is2
* Set if TCP sequence number is 0, LAN966x: Overlayed with PTP over UDP:
* messageType bit 0
* VCAP_KF_L4_SPORT: W16, sparx5: is2
* TCP/UDP source port
* VCAP_KF_L4_SPORT_EQ_DPORT_IS: W1, sparx5: is2
* Set if UDP or TCP source port equals UDP or TCP destination port
* VCAP_KF_L4_SYN: W1, sparx5: is2
* Sparx5: TCP flag SYN, LAN966x: TCP: TCP flag SYN. PTP over UDP: messageType
* bit 2
* VCAP_KF_L4_URG: W1, sparx5: is2
* Sparx5: TCP flag URG, LAN966x: TCP: TCP flag URG. PTP over UDP: flagField bit
* 7 (reserved)
* VCAP_KF_LOOKUP_FIRST_IS: W1, sparx5: is2
* Selects between entries relevant for first and second lookup. Set for first
* lookup, cleared for second lookup.
* VCAP_KF_LOOKUP_PAG: W8, sparx5: is2
* Classified Policy Association Group: chains rules from IS1/CLM to IS2
* VCAP_KF_OAM_CCM_CNTS_EQ0: W1, sparx5: is2
* Dual-ended loss measurement counters in CCM frames are all zero
* VCAP_KF_OAM_Y1731_IS: W1, sparx5: is2
* Set if frame’s EtherType = 0x8902
* VCAP_KF_TCP_IS: W1, sparx5: is2
* Set if frame is IPv4 TCP frame (IP protocol = 6) or IPv6 TCP frames (Next
* header = 6)
* VCAP_KF_TCP_UDP_IS: W1, sparx5: is2
* Set if frame is IPv4/IPv6 TCP or UDP frame (IP protocol/next header equals 6
* or 17)
* VCAP_KF_TYPE: sparx5 is2 W4, sparx5 is2 W2
* Keyset type id - set by the API
*/
/* Keyfield names */
enum vcap_key_field {
VCAP_KF_NO_VALUE, /* initial value */
VCAP_KF_8021Q_DEI_CLS,
VCAP_KF_8021Q_PCP_CLS,
VCAP_KF_8021Q_VID_CLS,
VCAP_KF_8021Q_VLAN_TAGGED_IS,
VCAP_KF_ARP_ADDR_SPACE_OK_IS,
VCAP_KF_ARP_LEN_OK_IS,
VCAP_KF_ARP_OPCODE,
VCAP_KF_ARP_OPCODE_UNKNOWN_IS,
VCAP_KF_ARP_PROTO_SPACE_OK_IS,
VCAP_KF_ARP_SENDER_MATCH_IS,
VCAP_KF_ARP_TGT_MATCH_IS,
VCAP_KF_ETYPE,
VCAP_KF_ETYPE_LEN_IS,
VCAP_KF_IF_IGR_PORT_MASK,
VCAP_KF_IF_IGR_PORT_MASK_L3,
VCAP_KF_IF_IGR_PORT_MASK_RNG,
VCAP_KF_IF_IGR_PORT_MASK_SEL,
VCAP_KF_IP4_IS,
VCAP_KF_ISDX_CLS,
VCAP_KF_ISDX_GT0_IS,
VCAP_KF_L2_BC_IS,
VCAP_KF_L2_DMAC,
VCAP_KF_L2_FWD_IS,
VCAP_KF_L2_MC_IS,
VCAP_KF_L2_PAYLOAD_ETYPE,
VCAP_KF_L2_SMAC,
VCAP_KF_L3_DIP_EQ_SIP_IS,
VCAP_KF_L3_DST_IS,
VCAP_KF_L3_FRAGMENT_TYPE,
VCAP_KF_L3_FRAG_INVLD_L4_LEN,
VCAP_KF_L3_IP4_DIP,
VCAP_KF_L3_IP4_SIP,
VCAP_KF_L3_IP6_DIP,
VCAP_KF_L3_IP6_SIP,
VCAP_KF_L3_IP_PROTO,
VCAP_KF_L3_OPTIONS_IS,
VCAP_KF_L3_PAYLOAD,
VCAP_KF_L3_RT_IS,
VCAP_KF_L3_TOS,
VCAP_KF_L3_TTL_GT0,
VCAP_KF_L4_ACK,
VCAP_KF_L4_DPORT,
VCAP_KF_L4_FIN,
VCAP_KF_L4_PAYLOAD,
VCAP_KF_L4_PSH,
VCAP_KF_L4_RNG,
VCAP_KF_L4_RST,
VCAP_KF_L4_SEQUENCE_EQ0_IS,
VCAP_KF_L4_SPORT,
VCAP_KF_L4_SPORT_EQ_DPORT_IS,
VCAP_KF_L4_SYN,
VCAP_KF_L4_URG,
VCAP_KF_LOOKUP_FIRST_IS,
VCAP_KF_LOOKUP_PAG,
VCAP_KF_OAM_CCM_CNTS_EQ0,
VCAP_KF_OAM_Y1731_IS,
VCAP_KF_TCP_IS,
VCAP_KF_TCP_UDP_IS,
VCAP_KF_TYPE,
};
/* Actionset names with origin information */
enum vcap_actionfield_set {
VCAP_AFS_NO_VALUE, /* initial value */
VCAP_AFS_BASE_TYPE, /* sparx5 is2 X3 */
};
/* List of actionfields with description
*
* VCAP_AF_CNT_ID: W12, sparx5: is2
* Counter ID, used per lookup to index the 4K frame counters (ANA_ACL:CNT_TBL).
* Multiple VCAP IS2 entries can use the same counter.
* VCAP_AF_CPU_COPY_ENA: W1, sparx5: is2
* Setting this bit to 1 causes all frames that hit this action to be copied to
* the CPU extraction queue specified in CPU_QUEUE_NUM.
* VCAP_AF_CPU_QUEUE_NUM: W3, sparx5: is2
* CPU queue number. Used when CPU_COPY_ENA is set.
* VCAP_AF_HIT_ME_ONCE: W1, sparx5: is2
* Setting this bit to 1 causes the first frame that hits this action where the
* HIT_CNT counter is zero to be copied to the CPU extraction queue specified in
* CPU_QUEUE_NUM. The HIT_CNT counter is then incremented and any frames that
* hit this action later are not copied to the CPU. To re-enable the HIT_ME_ONCE
* functionality, the HIT_CNT counter must be cleared.
* VCAP_AF_IGNORE_PIPELINE_CTRL: W1, sparx5: is2
* Ignore ingress pipeline control. This enforces the use of the VCAP IS2 action
* even when the pipeline control has terminated the frame before VCAP IS2.
* VCAP_AF_INTR_ENA: W1, sparx5: is2
* If set, an interrupt is triggered when this rule is hit
* VCAP_AF_LRN_DIS: W1, sparx5: is2
* Setting this bit to 1 disables learning of frames hitting this action.
* VCAP_AF_MASK_MODE: W3, sparx5: is2
* Controls the PORT_MASK use. Sparx5: 0: OR_DSTMASK, 1: AND_VLANMASK, 2:
* REPLACE_PGID, 3: REPLACE_ALL, 4: REDIR_PGID, 5: OR_PGID_MASK, 6: VSTAX, 7:
* Not applicable. LAN966X: 0: No action, 1: Permit/deny (AND), 2: Policy
* forwarding (DMAC lookup), 3: Redirect. The CPU port is untouched by
* MASK_MODE.
* VCAP_AF_MATCH_ID: W16, sparx5: is2
* Logical ID for the entry. The MATCH_ID is extracted together with the frame
* if the frame is forwarded to the CPU (CPU_COPY_ENA). The result is placed in
* IFH.CL_RSLT.
* VCAP_AF_MATCH_ID_MASK: W16, sparx5: is2
* Mask used by MATCH_ID.
* VCAP_AF_MIRROR_PROBE: W2, sparx5: is2
* Mirroring performed according to configuration of a mirror probe. 0: No
* mirroring. 1: Mirror probe 0. 2: Mirror probe 1. 3: Mirror probe 2
* VCAP_AF_PIPELINE_FORCE_ENA: W1, sparx5: is2
* If set, use PIPELINE_PT unconditionally and set PIPELINE_ACT = NONE if
* PIPELINE_PT == NONE. Overrules previous settings of pipeline point.
* VCAP_AF_PIPELINE_PT: W5, sparx5: is2
* Pipeline point used if PIPELINE_FORCE_ENA is set
* VCAP_AF_POLICE_ENA: W1, sparx5: is2
* Setting this bit to 1 causes frames that hit this action to be policed by the
* ACL policer specified in POLICE_IDX. Only applies to the first lookup.
* VCAP_AF_POLICE_IDX: W6, sparx5: is2
* Selects VCAP policer used when policing frames (POLICE_ENA)
* VCAP_AF_PORT_MASK: W68, sparx5: is2
* Port mask applied to the forwarding decision based on MASK_MODE.
* VCAP_AF_RT_DIS: W1, sparx5: is2
* If set, routing is disallowed. Only applies when IS_INNER_ACL is 0. See also
* IGR_ACL_ENA, EGR_ACL_ENA, and RLEG_STAT_IDX.
*/
/* Actionfield names */
enum vcap_action_field {
VCAP_AF_NO_VALUE, /* initial value */
VCAP_AF_CNT_ID,
VCAP_AF_CPU_COPY_ENA,
VCAP_AF_CPU_QUEUE_NUM,
VCAP_AF_HIT_ME_ONCE,
VCAP_AF_IGNORE_PIPELINE_CTRL,
VCAP_AF_INTR_ENA,
VCAP_AF_LRN_DIS,
VCAP_AF_MASK_MODE,
VCAP_AF_MATCH_ID,
VCAP_AF_MATCH_ID_MASK,
VCAP_AF_MIRROR_PROBE,
VCAP_AF_PIPELINE_FORCE_ENA,
VCAP_AF_PIPELINE_PT,
VCAP_AF_POLICE_ENA,
VCAP_AF_POLICE_IDX,
VCAP_AF_PORT_MASK,
VCAP_AF_RT_DIS,
};
#endif /* __VCAP_AG_API__ */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP test model interface for kunit testing
*/
#ifndef __VCAP_MODEL_KUNIT_H__
#define __VCAP_MODEL_KUNIT_H__
extern const struct vcap_info kunit_test_vcaps[];
extern const struct vcap_statistics kunit_test_vcap_stats;
#endif /* __VCAP_MODEL_KUNIT_H__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册