Commit cb55ff7a authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'add-support-for-lan966x-is2-vcap'

Horatiu Vultur says:

====================
Add support for lan966x IS2 VCAP

This provides initial support for lan966x for 'tc' traffic control
userspace tool and its flower filter. For this is required to use
the VCAP library.

Currently supported flower filter keys and actions are:
- source and destination MAC address keys
- trap action
====================

Link: https://lore.kernel.org/r/20221125095010.124458-1-horatiu.vultur@microchip.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 7a168f56 4f141e36
......@@ -8,5 +8,6 @@ config LAN966X_SWITCH
select PHYLINK
select PACKING
select PAGE_POOL
select VCAP
help
This driver supports the Lan966x network switch device.
......@@ -12,4 +12,8 @@ lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
lan966x_tc.o lan966x_mqprio.o lan966x_taprio.o \
lan966x_tbf.o lan966x_cbs.o lan966x_ets.o \
lan966x_tc_matchall.o lan966x_police.o lan966x_mirror.o \
lan966x_xdp.o
lan966x_xdp.o lan966x_vcap_impl.o lan966x_vcap_ag_api.o \
lan966x_tc_flower.o lan966x_goto.o
# Provide include files
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap
// SPDX-License-Identifier: GPL-2.0+
#include "lan966x_main.h"
#include "vcap_api_client.h"
int lan966x_goto_port_add(struct lan966x_port *port,
struct flow_action_entry *act,
unsigned long goto_id,
struct netlink_ext_ack *extack)
{
struct lan966x *lan966x = port->lan966x;
int err;
err = vcap_enable_lookups(lan966x->vcap_ctrl, port->dev,
act->chain_index, goto_id,
true);
if (err == -EFAULT) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported goto chain");
return -EOPNOTSUPP;
}
if (err == -EADDRINUSE) {
NL_SET_ERR_MSG_MOD(extack, "VCAP already enabled");
return -EOPNOTSUPP;
}
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Could not enable VCAP lookups");
return err;
}
port->tc.goto_id = goto_id;
return 0;
}
int lan966x_goto_port_del(struct lan966x_port *port,
unsigned long goto_id,
struct netlink_ext_ack *extack)
{
struct lan966x *lan966x = port->lan966x;
int err;
err = vcap_enable_lookups(lan966x->vcap_ctrl, port->dev, 0,
goto_id, false);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Could not disable VCAP lookups");
return err;
}
port->tc.goto_id = 0;
return 0;
}
......@@ -47,6 +47,9 @@ static const struct lan966x_main_io_resource lan966x_main_iomap[] = {
{ TARGET_PTP, 0xc000, 1 }, /* 0xe200c000 */
{ TARGET_CHIP_TOP, 0x10000, 1 }, /* 0xe2010000 */
{ TARGET_REW, 0x14000, 1 }, /* 0xe2014000 */
{ TARGET_VCAP, 0x18000, 1 }, /* 0xe2018000 */
{ TARGET_VCAP + 1, 0x20000, 1 }, /* 0xe2020000 */
{ TARGET_VCAP + 2, 0x24000, 1 }, /* 0xe2024000 */
{ TARGET_SYS, 0x28000, 1 }, /* 0xe2028000 */
{ TARGET_DEV, 0x34000, 1 }, /* 0xe2034000 */
{ TARGET_DEV + 1, 0x38000, 1 }, /* 0xe2038000 */
......@@ -1157,8 +1160,15 @@ static int lan966x_probe(struct platform_device *pdev)
if (err)
goto cleanup_ptp;
err = lan966x_vcap_init(lan966x);
if (err)
goto cleanup_fdma;
return 0;
cleanup_fdma:
lan966x_fdma_deinit(lan966x);
cleanup_ptp:
lan966x_ptp_deinit(lan966x);
......@@ -1182,6 +1192,7 @@ static int lan966x_remove(struct platform_device *pdev)
struct lan966x *lan966x = platform_get_drvdata(pdev);
lan966x_taprio_deinit(lan966x);
lan966x_vcap_deinit(lan966x);
lan966x_fdma_deinit(lan966x);
lan966x_cleanup_ports(lan966x);
......
......@@ -300,6 +300,9 @@ struct lan966x {
struct lan966x_port *mirror_monitor;
u32 mirror_mask[2];
u32 mirror_count;
/* vcap */
struct vcap_control *vcap_ctrl;
};
struct lan966x_port_config {
......@@ -317,6 +320,7 @@ struct lan966x_port_tc {
unsigned long police_id;
unsigned long ingress_mirror_id;
unsigned long egress_mirror_id;
unsigned long goto_id;
struct flow_stats police_stat;
struct flow_stats mirror_stat;
};
......@@ -582,6 +586,20 @@ static inline bool lan966x_xdp_port_present(struct lan966x_port *port)
return !!port->xdp_prog;
}
int lan966x_vcap_init(struct lan966x *lan966x);
void lan966x_vcap_deinit(struct lan966x *lan966x);
int lan966x_tc_flower(struct lan966x_port *port,
struct flow_cls_offload *f);
int lan966x_goto_port_add(struct lan966x_port *port,
struct flow_action_entry *act,
unsigned long goto_id,
struct netlink_ext_ack *extack);
int lan966x_goto_port_del(struct lan966x_port *port,
unsigned long goto_id,
struct netlink_ext_ack *extack);
static inline void __iomem *lan_addr(void __iomem *base[],
int id, int tinst, int tcnt,
int gbase, int ginst,
......
......@@ -25,6 +25,7 @@ enum lan966x_target {
TARGET_QSYS = 46,
TARGET_REW = 47,
TARGET_SYS = 52,
TARGET_VCAP = 61,
NUM_TARGETS = 66
};
......@@ -315,6 +316,69 @@ enum lan966x_target {
#define ANA_DROP_CFG_DROP_MC_SMAC_ENA_GET(x)\
FIELD_GET(ANA_DROP_CFG_DROP_MC_SMAC_ENA, x)
/* ANA:PORT:VCAP_S2_CFG */
#define ANA_VCAP_S2_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 28, 0, 1, 4)
#define ANA_VCAP_S2_CFG_ISDX_ENA GENMASK(20, 19)
#define ANA_VCAP_S2_CFG_ISDX_ENA_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_ISDX_ENA, x)
#define ANA_VCAP_S2_CFG_ISDX_ENA_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_ISDX_ENA, x)
#define ANA_VCAP_S2_CFG_UDP_PAYLOAD_ENA GENMASK(18, 17)
#define ANA_VCAP_S2_CFG_UDP_PAYLOAD_ENA_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_UDP_PAYLOAD_ENA, x)
#define ANA_VCAP_S2_CFG_UDP_PAYLOAD_ENA_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_UDP_PAYLOAD_ENA, x)
#define ANA_VCAP_S2_CFG_ETYPE_PAYLOAD_ENA GENMASK(16, 15)
#define ANA_VCAP_S2_CFG_ETYPE_PAYLOAD_ENA_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_ETYPE_PAYLOAD_ENA, x)
#define ANA_VCAP_S2_CFG_ETYPE_PAYLOAD_ENA_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_ETYPE_PAYLOAD_ENA, x)
#define ANA_VCAP_S2_CFG_ENA BIT(14)
#define ANA_VCAP_S2_CFG_ENA_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_ENA, x)
#define ANA_VCAP_S2_CFG_ENA_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_ENA, x)
#define ANA_VCAP_S2_CFG_SNAP_DIS GENMASK(13, 12)
#define ANA_VCAP_S2_CFG_SNAP_DIS_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_SNAP_DIS, x)
#define ANA_VCAP_S2_CFG_SNAP_DIS_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_SNAP_DIS, x)
#define ANA_VCAP_S2_CFG_ARP_DIS GENMASK(11, 10)
#define ANA_VCAP_S2_CFG_ARP_DIS_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_ARP_DIS, x)
#define ANA_VCAP_S2_CFG_ARP_DIS_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_ARP_DIS, x)
#define ANA_VCAP_S2_CFG_IP_TCPUDP_DIS GENMASK(9, 8)
#define ANA_VCAP_S2_CFG_IP_TCPUDP_DIS_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_IP_TCPUDP_DIS, x)
#define ANA_VCAP_S2_CFG_IP_TCPUDP_DIS_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_IP_TCPUDP_DIS, x)
#define ANA_VCAP_S2_CFG_IP_OTHER_DIS GENMASK(7, 6)
#define ANA_VCAP_S2_CFG_IP_OTHER_DIS_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_IP_OTHER_DIS, x)
#define ANA_VCAP_S2_CFG_IP_OTHER_DIS_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_IP_OTHER_DIS, x)
#define ANA_VCAP_S2_CFG_IP6_CFG GENMASK(5, 2)
#define ANA_VCAP_S2_CFG_IP6_CFG_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_IP6_CFG, x)
#define ANA_VCAP_S2_CFG_IP6_CFG_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_IP6_CFG, x)
#define ANA_VCAP_S2_CFG_OAM_DIS GENMASK(1, 0)
#define ANA_VCAP_S2_CFG_OAM_DIS_SET(x)\
FIELD_PREP(ANA_VCAP_S2_CFG_OAM_DIS, x)
#define ANA_VCAP_S2_CFG_OAM_DIS_GET(x)\
FIELD_GET(ANA_VCAP_S2_CFG_OAM_DIS, x)
/* ANA:PORT:CPU_FWD_CFG */
#define ANA_CPU_FWD_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 96, 0, 1, 4)
......@@ -1506,4 +1570,136 @@ enum lan966x_target {
#define SYS_RAM_INIT_RAM_INIT_GET(x)\
FIELD_GET(SYS_RAM_INIT_RAM_INIT, x)
/* VCAP:VCAP_CORE_CFG:VCAP_UPDATE_CTRL */
#define VCAP_UPDATE_CTRL(t) __REG(TARGET_VCAP, t, 3, 0, 0, 1, 8, 0, 0, 1, 4)
#define VCAP_UPDATE_CTRL_UPDATE_CMD GENMASK(24, 22)
#define VCAP_UPDATE_CTRL_UPDATE_CMD_SET(x)\
FIELD_PREP(VCAP_UPDATE_CTRL_UPDATE_CMD, x)
#define VCAP_UPDATE_CTRL_UPDATE_CMD_GET(x)\
FIELD_GET(VCAP_UPDATE_CTRL_UPDATE_CMD, x)
#define VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS BIT(21)
#define VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(x)\
FIELD_PREP(VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS, x)
#define VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_GET(x)\
FIELD_GET(VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS, x)
#define VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS BIT(20)
#define VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(x)\
FIELD_PREP(VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS, x)
#define VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_GET(x)\
FIELD_GET(VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS, x)
#define VCAP_UPDATE_CTRL_UPDATE_CNT_DIS BIT(19)
#define VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(x)\
FIELD_PREP(VCAP_UPDATE_CTRL_UPDATE_CNT_DIS, x)
#define VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_GET(x)\
FIELD_GET(VCAP_UPDATE_CTRL_UPDATE_CNT_DIS, x)
#define VCAP_UPDATE_CTRL_UPDATE_ADDR GENMASK(18, 3)
#define VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(x)\
FIELD_PREP(VCAP_UPDATE_CTRL_UPDATE_ADDR, x)
#define VCAP_UPDATE_CTRL_UPDATE_ADDR_GET(x)\
FIELD_GET(VCAP_UPDATE_CTRL_UPDATE_ADDR, x)
#define VCAP_UPDATE_CTRL_UPDATE_SHOT BIT(2)
#define VCAP_UPDATE_CTRL_UPDATE_SHOT_SET(x)\
FIELD_PREP(VCAP_UPDATE_CTRL_UPDATE_SHOT, x)
#define VCAP_UPDATE_CTRL_UPDATE_SHOT_GET(x)\
FIELD_GET(VCAP_UPDATE_CTRL_UPDATE_SHOT, x)
#define VCAP_UPDATE_CTRL_CLEAR_CACHE BIT(1)
#define VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(x)\
FIELD_PREP(VCAP_UPDATE_CTRL_CLEAR_CACHE, x)
#define VCAP_UPDATE_CTRL_CLEAR_CACHE_GET(x)\
FIELD_GET(VCAP_UPDATE_CTRL_CLEAR_CACHE, x)
#define VCAP_UPDATE_CTRL_MV_TRAFFIC_IGN BIT(0)
#define VCAP_UPDATE_CTRL_MV_TRAFFIC_IGN_SET(x)\
FIELD_PREP(VCAP_UPDATE_CTRL_MV_TRAFFIC_IGN, x)
#define VCAP_UPDATE_CTRL_MV_TRAFFIC_IGN_GET(x)\
FIELD_GET(VCAP_UPDATE_CTRL_MV_TRAFFIC_IGN, x)
/* VCAP:VCAP_CORE_CFG:VCAP_MV_CFG */
#define VCAP_MV_CFG(t) __REG(TARGET_VCAP, t, 3, 0, 0, 1, 8, 4, 0, 1, 4)
#define VCAP_MV_CFG_MV_NUM_POS GENMASK(31, 16)
#define VCAP_MV_CFG_MV_NUM_POS_SET(x)\
FIELD_PREP(VCAP_MV_CFG_MV_NUM_POS, x)
#define VCAP_MV_CFG_MV_NUM_POS_GET(x)\
FIELD_GET(VCAP_MV_CFG_MV_NUM_POS, x)
#define VCAP_MV_CFG_MV_SIZE GENMASK(15, 0)
#define VCAP_MV_CFG_MV_SIZE_SET(x)\
FIELD_PREP(VCAP_MV_CFG_MV_SIZE, x)
#define VCAP_MV_CFG_MV_SIZE_GET(x)\
FIELD_GET(VCAP_MV_CFG_MV_SIZE, x)
/* VCAP:VCAP_CORE_CACHE:VCAP_ENTRY_DAT */
#define VCAP_ENTRY_DAT(t, r) __REG(TARGET_VCAP, t, 3, 8, 0, 1, 904, 0, r, 64, 4)
/* VCAP:VCAP_CORE_CACHE:VCAP_MASK_DAT */
#define VCAP_MASK_DAT(t, r) __REG(TARGET_VCAP, t, 3, 8, 0, 1, 904, 256, r, 64, 4)
/* VCAP:VCAP_CORE_CACHE:VCAP_ACTION_DAT */
#define VCAP_ACTION_DAT(t, r) __REG(TARGET_VCAP, t, 3, 8, 0, 1, 904, 512, r, 64, 4)
/* VCAP:VCAP_CORE_CACHE:VCAP_CNT_DAT */
#define VCAP_CNT_DAT(t, r) __REG(TARGET_VCAP, t, 3, 8, 0, 1, 904, 768, r, 32, 4)
/* VCAP:VCAP_CORE_CACHE:VCAP_CNT_FW_DAT */
#define VCAP_CNT_FW_DAT(t) __REG(TARGET_VCAP, t, 3, 8, 0, 1, 904, 896, 0, 1, 4)
/* VCAP:VCAP_CORE_CACHE:VCAP_TG_DAT */
#define VCAP_TG_DAT(t) __REG(TARGET_VCAP, t, 3, 8, 0, 1, 904, 900, 0, 1, 4)
/* VCAP:VCAP_CORE_MAP:VCAP_CORE_IDX */
#define VCAP_CORE_IDX(t) __REG(TARGET_VCAP, t, 3, 912, 0, 1, 8, 0, 0, 1, 4)
#define VCAP_CORE_IDX_CORE_IDX GENMASK(3, 0)
#define VCAP_CORE_IDX_CORE_IDX_SET(x)\
FIELD_PREP(VCAP_CORE_IDX_CORE_IDX, x)
#define VCAP_CORE_IDX_CORE_IDX_GET(x)\
FIELD_GET(VCAP_CORE_IDX_CORE_IDX, x)
/* VCAP:VCAP_CORE_MAP:VCAP_CORE_MAP */
#define VCAP_CORE_MAP(t) __REG(TARGET_VCAP, t, 3, 912, 0, 1, 8, 4, 0, 1, 4)
#define VCAP_CORE_MAP_CORE_MAP GENMASK(2, 0)
#define VCAP_CORE_MAP_CORE_MAP_SET(x)\
FIELD_PREP(VCAP_CORE_MAP_CORE_MAP, x)
#define VCAP_CORE_MAP_CORE_MAP_GET(x)\
FIELD_GET(VCAP_CORE_MAP_CORE_MAP, x)
/* VCAP:VCAP_CONST:VCAP_VER */
#define VCAP_VER(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 0, 0, 1, 4)
/* VCAP:VCAP_CONST:ENTRY_WIDTH */
#define VCAP_ENTRY_WIDTH(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 4, 0, 1, 4)
/* VCAP:VCAP_CONST:ENTRY_CNT */
#define VCAP_ENTRY_CNT(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 8, 0, 1, 4)
/* VCAP:VCAP_CONST:ENTRY_SWCNT */
#define VCAP_ENTRY_SWCNT(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 12, 0, 1, 4)
/* VCAP:VCAP_CONST:ENTRY_TG_WIDTH */
#define VCAP_ENTRY_TG_WIDTH(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 16, 0, 1, 4)
/* VCAP:VCAP_CONST:ACTION_DEF_CNT */
#define VCAP_ACTION_DEF_CNT(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 20, 0, 1, 4)
/* VCAP:VCAP_CONST:ACTION_WIDTH */
#define VCAP_ACTION_WIDTH(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 24, 0, 1, 4)
/* VCAP:VCAP_CONST:CNT_WIDTH */
#define VCAP_CNT_WIDTH(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 28, 0, 1, 4)
/* VCAP:VCAP_CONST:CORE_CNT */
#define VCAP_CORE_CNT(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 32, 0, 1, 4)
/* VCAP:VCAP_CONST:IF_CNT */
#define VCAP_IF_CNT(t) __REG(TARGET_VCAP, t, 3, 924, 0, 1, 40, 36, 0, 1, 4)
#endif /* _LAN966X_REGS_H_ */
......@@ -69,6 +69,8 @@ static int lan966x_tc_block_cb(enum tc_setup_type type, void *type_data,
switch (type) {
case TC_SETUP_CLSMATCHALL:
return lan966x_tc_matchall(port, type_data, ingress);
case TC_SETUP_CLSFLOWER:
return lan966x_tc_flower(port, type_data);
default:
return -EOPNOTSUPP;
}
......
// SPDX-License-Identifier: GPL-2.0+
#include "lan966x_main.h"
#include "vcap_api.h"
#include "vcap_api_client.h"
/* Controls how PORT_MASK is applied */
enum LAN966X_PORT_MASK_MODE {
LAN966X_PMM_NO_ACTION,
LAN966X_PMM_REPLACE,
LAN966X_PMM_FORWARDING,
LAN966X_PMM_REDIRECT,
};
struct lan966x_tc_flower_parse_usage {
struct flow_cls_offload *f;
struct flow_rule *frule;
struct vcap_rule *vrule;
unsigned int used_keys;
u16 l3_proto;
};
static int lan966x_tc_flower_handler_ethaddr_usage(struct lan966x_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->f->common.extack, "eth_addr parse error");
return err;
}
static int
(*lan966x_tc_flower_handlers_usage[])(struct lan966x_tc_flower_parse_usage *st) = {
[FLOW_DISSECTOR_KEY_ETH_ADDRS] = lan966x_tc_flower_handler_ethaddr_usage,
};
static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f,
struct vcap_admin *admin,
struct vcap_rule *vrule,
u16 *l3_proto)
{
struct lan966x_tc_flower_parse_usage state = {
.f = f,
.vrule = vrule,
.l3_proto = ETH_P_ALL,
};
int err = 0;
state.frule = flow_cls_offload_flow_rule(f);
for (int i = 0; i < ARRAY_SIZE(lan966x_tc_flower_handlers_usage); ++i) {
if (!flow_rule_match_key(state.frule, i) ||
!lan966x_tc_flower_handlers_usage[i])
continue;
err = lan966x_tc_flower_handlers_usage[i](&state);
if (err)
return err;
}
if (l3_proto)
*l3_proto = state.l3_proto;
return err;
}
static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
struct flow_cls_offload *fco,
struct vcap_admin *admin)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
struct flow_action_entry *actent, *last_actent = NULL;
struct flow_action *act = &rule->action;
u64 action_mask = 0;
int idx;
if (!flow_action_has_entries(act)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
return -EINVAL;
}
if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
return -EOPNOTSUPP;
flow_action_for_each(idx, actent, act) {
if (action_mask & BIT(actent->id)) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"More actions of the same type");
return -EINVAL;
}
action_mask |= BIT(actent->id);
last_actent = actent; /* Save last action for later check */
}
/* Check that last action is a goto */
if (last_actent->id != FLOW_ACTION_GOTO) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Last action must be 'goto'");
return -EINVAL;
}
/* Check if the goto chain is in the next lookup */
if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
last_actent->chain_index)) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Invalid goto chain");
return -EINVAL;
}
/* Catch unsupported combinations of actions */
if (action_mask & BIT(FLOW_ACTION_TRAP) &&
action_mask & BIT(FLOW_ACTION_ACCEPT)) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Cannot combine pass and trap action");
return -EOPNOTSUPP;
}
return 0;
}
static int lan966x_tc_flower_add(struct lan966x_port *port,
struct flow_cls_offload *f,
struct vcap_admin *admin)
{
struct flow_action_entry *act;
u16 l3_proto = ETH_P_ALL;
struct flow_rule *frule;
struct vcap_rule *vrule;
int err, idx;
err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, f,
admin);
if (err)
return err;
vrule = vcap_alloc_rule(port->lan966x->vcap_ctrl, port->dev,
f->common.chain_index, VCAP_USER_TC,
f->common.prio, 0);
if (IS_ERR(vrule))
return PTR_ERR(vrule);
vrule->cookie = f->cookie;
err = lan966x_tc_flower_use_dissectors(f, admin, vrule, &l3_proto);
if (err)
goto out;
frule = flow_cls_offload_flow_rule(f);
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);
err |= vcap_rule_add_action_u32(vrule,
VCAP_AF_CPU_QUEUE_NUM,
0);
err |= vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE,
LAN966X_PMM_REPLACE);
err |= vcap_set_rule_set_actionset(vrule,
VCAP_AFS_BASE_TYPE);
if (err)
goto out;
break;
case FLOW_ACTION_GOTO:
break;
default:
NL_SET_ERR_MSG_MOD(f->common.extack,
"Unsupported TC action");
err = -EOPNOTSUPP;
goto out;
}
}
err = vcap_val_rule(vrule, l3_proto);
if (err) {
vcap_set_tc_exterr(f, vrule);
goto out;
}
err = vcap_add_rule(vrule);
if (err)
NL_SET_ERR_MSG_MOD(f->common.extack,
"Could not add the filter");
out:
vcap_free_rule(vrule);
return err;
}
static int lan966x_tc_flower_del(struct lan966x_port *port,
struct flow_cls_offload *f,
struct vcap_admin *admin)
{
struct vcap_control *vctrl;
int err = -ENOENT, rule_id;
vctrl = port->lan966x->vcap_ctrl;
while (true) {
rule_id = vcap_lookup_rule_by_cookie(vctrl, f->cookie);
if (rule_id <= 0)
break;
err = vcap_del_rule(vctrl, port->dev, rule_id);
if (err) {
NL_SET_ERR_MSG_MOD(f->common.extack,
"Cannot delete rule");
break;
}
}
return err;
}
int lan966x_tc_flower(struct lan966x_port *port,
struct flow_cls_offload *f)
{
struct vcap_admin *admin;
admin = vcap_find_admin(port->lan966x->vcap_ctrl,
f->common.chain_index);
if (!admin) {
NL_SET_ERR_MSG_MOD(f->common.extack, "Invalid chain");
return -EINVAL;
}
switch (f->command) {
case FLOW_CLS_REPLACE:
return lan966x_tc_flower_add(port, f, admin);
case FLOW_CLS_DESTROY:
return lan966x_tc_flower_del(port, f, admin);
default:
return -EOPNOTSUPP;
}
return 0;
}
......@@ -23,6 +23,9 @@ static int lan966x_tc_matchall_add(struct lan966x_port *port,
case FLOW_ACTION_MIRRED:
return lan966x_mirror_port_add(port, act, f->cookie,
ingress, f->common.extack);
case FLOW_ACTION_GOTO:
return lan966x_goto_port_add(port, act, f->cookie,
f->common.extack);
default:
NL_SET_ERR_MSG_MOD(f->common.extack,
"Unsupported action");
......@@ -43,6 +46,9 @@ static int lan966x_tc_matchall_del(struct lan966x_port *port,
f->cookie == port->tc.egress_mirror_id) {
return lan966x_mirror_port_del(port, ingress,
f->common.extack);
} else if (f->cookie == port->tc.goto_id) {
return lan966x_goto_port_del(port, f->cookie,
f->common.extack);
} else {
NL_SET_ERR_MSG_MOD(f->common.extack,
"Unsupported action");
......
This diff is collapsed.
/* SPDX-License-Identifier: BSD-3-Clause */
#ifndef __LAN966X_VCAP_AG_API_H__
#define __LAN966X_VCAP_AG_API_H__
#include "vcap_api.h"
extern const struct vcap_info lan966x_vcaps[];
extern const struct vcap_statistics lan966x_vcap_stats;
#endif /* __LAN966X_VCAP_AG_API_H__ */
This diff is collapsed.
......@@ -8,6 +8,28 @@
#include "vcap_api_private.h"
static int keyfield_size_table[] = {
[VCAP_FIELD_BIT] = sizeof(struct vcap_u1_key),
[VCAP_FIELD_U32] = sizeof(struct vcap_u32_key),
[VCAP_FIELD_U48] = sizeof(struct vcap_u48_key),
[VCAP_FIELD_U56] = sizeof(struct vcap_u56_key),
[VCAP_FIELD_U64] = sizeof(struct vcap_u64_key),
[VCAP_FIELD_U72] = sizeof(struct vcap_u72_key),
[VCAP_FIELD_U112] = sizeof(struct vcap_u112_key),
[VCAP_FIELD_U128] = sizeof(struct vcap_u128_key),
};
static int actionfield_size_table[] = {
[VCAP_FIELD_BIT] = sizeof(struct vcap_u1_action),
[VCAP_FIELD_U32] = sizeof(struct vcap_u32_action),
[VCAP_FIELD_U48] = sizeof(struct vcap_u48_action),
[VCAP_FIELD_U56] = sizeof(struct vcap_u56_action),
[VCAP_FIELD_U64] = sizeof(struct vcap_u64_action),
[VCAP_FIELD_U72] = sizeof(struct vcap_u72_action),
[VCAP_FIELD_U112] = sizeof(struct vcap_u112_action),
[VCAP_FIELD_U128] = sizeof(struct vcap_u128_action),
};
/* Moving a rule in the VCAP address space */
struct vcap_rule_move {
int addr; /* address to move */
......@@ -1312,12 +1334,67 @@ const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
}
EXPORT_SYMBOL_GPL(vcap_lookup_keyfield);
/* Copy data from src to dst but reverse the data in chunks of 32bits.
* For example if src is 00:11:22:33:44:55 where 55 is LSB the dst will
* have the value 22:33:44:55:00:11.
*/
static void vcap_copy_to_w32be(u8 *dst, u8 *src, int size)
{
for (int idx = 0; idx < size; ++idx) {
int first_byte_index = 0;
int nidx;
first_byte_index = size - (((idx >> 2) + 1) << 2);
if (first_byte_index < 0)
first_byte_index = 0;
nidx = idx + first_byte_index - (idx & ~0x3);
dst[nidx] = src[idx];
}
}
static void vcap_copy_from_client_keyfield(struct vcap_rule *rule,
struct vcap_client_keyfield *field,
struct vcap_client_keyfield_data *data)
{
/* This will be expanded later to handle different vcap memory layouts */
memcpy(&field->data, data, sizeof(field->data));
struct vcap_rule_internal *ri = to_intrule(rule);
int size;
if (!ri->admin->w32be) {
memcpy(&field->data, data, sizeof(field->data));
return;
}
size = keyfield_size_table[field->ctrl.type] / 2;
switch (field->ctrl.type) {
case VCAP_FIELD_BIT:
case VCAP_FIELD_U32:
memcpy(&field->data, data, sizeof(field->data));
break;
case VCAP_FIELD_U48:
vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size);
vcap_copy_to_w32be(field->data.u48.mask, data->u48.mask, size);
break;
case VCAP_FIELD_U56:
vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size);
vcap_copy_to_w32be(field->data.u56.mask, data->u56.mask, size);
break;
case VCAP_FIELD_U64:
vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size);
vcap_copy_to_w32be(field->data.u64.mask, data->u64.mask, size);
break;
case VCAP_FIELD_U72:
vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size);
vcap_copy_to_w32be(field->data.u72.mask, data->u72.mask, size);
break;
case VCAP_FIELD_U112:
vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size);
vcap_copy_to_w32be(field->data.u112.mask, data->u112.mask, size);
break;
case VCAP_FIELD_U128:
vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size);
vcap_copy_to_w32be(field->data.u128.mask, data->u128.mask, size);
break;
};
}
/* Check if the keyfield is already in the rule */
......@@ -1475,8 +1552,39 @@ static void vcap_copy_from_client_actionfield(struct vcap_rule *rule,
struct vcap_client_actionfield *field,
struct vcap_client_actionfield_data *data)
{
/* This will be expanded later to handle different vcap memory layouts */
memcpy(&field->data, data, sizeof(field->data));
struct vcap_rule_internal *ri = to_intrule(rule);
int size;
if (!ri->admin->w32be) {
memcpy(&field->data, data, sizeof(field->data));
return;
}
size = actionfield_size_table[field->ctrl.type];
switch (field->ctrl.type) {
case VCAP_FIELD_BIT:
case VCAP_FIELD_U32:
memcpy(&field->data, data, sizeof(field->data));
break;
case VCAP_FIELD_U48:
vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size);
break;
case VCAP_FIELD_U56:
vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size);
break;
case VCAP_FIELD_U64:
vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size);
break;
case VCAP_FIELD_U72:
vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size);
break;
case VCAP_FIELD_U112:
vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size);
break;
case VCAP_FIELD_U128:
vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size);
break;
};
}
/* Check if the actionfield is already in the rule */
......
......@@ -11,9 +11,6 @@
#include <linux/netdevice.h>
/* Use the generated API model */
#ifdef CONFIG_VCAP_KUNIT_TEST
#include "vcap_ag_api_kunit.h"
#endif
#include "vcap_ag_api.h"
#define VCAP_CID_LOOKUP_SIZE 100000 /* Chains in a lookup */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment