Commit 99507e76 authored by David S. Miller's avatar David S. Miller

Merge branch 'lan966x-police-mirroring'

Horatiu Vultur says:

====================
net: lan966x: Add police and mirror using tc-matchall

Add tc-matchall classifier offload support both for ingress and egress.
For this add support for the port police and port mirroring action support.
Port police can happen only on ingress while port mirroring is supported
both on ingress and egress
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 95698ff6 b69e9539
......@@ -10,4 +10,5 @@ lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
lan966x_vlan.o lan966x_fdb.o lan966x_mdb.o \
lan966x_ptp.o lan966x_fdma.o lan966x_lag.o \
lan966x_tc.o lan966x_mqprio.o lan966x_taprio.o \
lan966x_tbf.o lan966x_cbs.o lan966x_ets.o
lan966x_tbf.o lan966x_cbs.o lan966x_ets.o \
lan966x_tc_matchall.o lan966x_police.o lan966x_mirror.o
......@@ -264,6 +264,11 @@ struct lan966x {
struct lan966x_rx rx;
struct lan966x_tx tx;
struct napi_struct napi;
/* Mirror */
struct lan966x_port *mirror_monitor;
u32 mirror_mask[2];
u32 mirror_count;
};
struct lan966x_port_config {
......@@ -276,6 +281,15 @@ struct lan966x_port_config {
bool autoneg;
};
struct lan966x_port_tc {
bool ingress_shared_block;
unsigned long police_id;
unsigned long ingress_mirror_id;
unsigned long egress_mirror_id;
struct flow_stats police_stat;
struct flow_stats mirror_stat;
};
struct lan966x_port {
struct net_device *dev;
struct lan966x *lan966x;
......@@ -302,6 +316,8 @@ struct lan966x_port {
struct net_device *bond;
bool lag_tx_active;
enum netdev_lag_hash hash_type;
struct lan966x_port_tc tc;
};
extern const struct phylink_mac_ops lan966x_phylink_mac_ops;
......@@ -481,6 +497,34 @@ int lan966x_ets_add(struct lan966x_port *port,
int lan966x_ets_del(struct lan966x_port *port,
struct tc_ets_qopt_offload *qopt);
int lan966x_tc_matchall(struct lan966x_port *port,
struct tc_cls_matchall_offload *f,
bool ingress);
int lan966x_police_port_add(struct lan966x_port *port,
struct flow_action *action,
struct flow_action_entry *act,
unsigned long police_id,
bool ingress,
struct netlink_ext_ack *extack);
int lan966x_police_port_del(struct lan966x_port *port,
unsigned long police_id,
struct netlink_ext_ack *extack);
void lan966x_police_port_stats(struct lan966x_port *port,
struct flow_stats *stats);
int lan966x_mirror_port_add(struct lan966x_port *port,
struct flow_action_entry *action,
unsigned long mirror_id,
bool ingress,
struct netlink_ext_ack *extack);
int lan966x_mirror_port_del(struct lan966x_port *port,
bool ingress,
struct netlink_ext_ack *extack);
void lan966x_mirror_port_stats(struct lan966x_port *port,
struct flow_stats *stats,
bool ingress);
static inline void __iomem *lan_addr(void __iomem *base[],
int id, int tinst, int tcnt,
int gbase, int ginst,
......
// SPDX-License-Identifier: GPL-2.0+
#include "lan966x_main.h"
int lan966x_mirror_port_add(struct lan966x_port *port,
struct flow_action_entry *action,
unsigned long mirror_id,
bool ingress,
struct netlink_ext_ack *extack)
{
struct lan966x *lan966x = port->lan966x;
struct lan966x_port *monitor_port;
if (!lan966x_netdevice_check(action->dev)) {
NL_SET_ERR_MSG_MOD(extack,
"Destination not an lan966x port");
return -EOPNOTSUPP;
}
monitor_port = netdev_priv(action->dev);
if (lan966x->mirror_mask[ingress] & BIT(port->chip_port)) {
NL_SET_ERR_MSG_MOD(extack,
"Mirror already exists");
return -EEXIST;
}
if (lan966x->mirror_monitor &&
lan966x->mirror_monitor != monitor_port) {
NL_SET_ERR_MSG_MOD(extack,
"Cannot change mirror port while in use");
return -EBUSY;
}
if (port == monitor_port) {
NL_SET_ERR_MSG_MOD(extack,
"Cannot mirror the monitor port");
return -EINVAL;
}
lan966x->mirror_mask[ingress] |= BIT(port->chip_port);
lan966x->mirror_monitor = monitor_port;
lan_wr(BIT(monitor_port->chip_port), lan966x, ANA_MIRRORPORTS);
if (ingress) {
lan_rmw(ANA_PORT_CFG_SRC_MIRROR_ENA_SET(1),
ANA_PORT_CFG_SRC_MIRROR_ENA,
lan966x, ANA_PORT_CFG(port->chip_port));
} else {
lan_wr(lan966x->mirror_mask[0], lan966x,
ANA_EMIRRORPORTS);
}
lan966x->mirror_count++;
if (ingress)
port->tc.ingress_mirror_id = mirror_id;
else
port->tc.egress_mirror_id = mirror_id;
return 0;
}
int lan966x_mirror_port_del(struct lan966x_port *port,
bool ingress,
struct netlink_ext_ack *extack)
{
struct lan966x *lan966x = port->lan966x;
if (!(lan966x->mirror_mask[ingress] & BIT(port->chip_port))) {
NL_SET_ERR_MSG_MOD(extack,
"There is no mirroring for this port");
return -ENOENT;
}
lan966x->mirror_mask[ingress] &= ~BIT(port->chip_port);
if (ingress) {
lan_rmw(ANA_PORT_CFG_SRC_MIRROR_ENA_SET(0),
ANA_PORT_CFG_SRC_MIRROR_ENA,
lan966x, ANA_PORT_CFG(port->chip_port));
} else {
lan_wr(lan966x->mirror_mask[0], lan966x,
ANA_EMIRRORPORTS);
}
lan966x->mirror_count--;
if (lan966x->mirror_count == 0) {
lan966x->mirror_monitor = NULL;
lan_wr(0, lan966x, ANA_MIRRORPORTS);
}
if (ingress)
port->tc.ingress_mirror_id = 0;
else
port->tc.egress_mirror_id = 0;
return 0;
}
void lan966x_mirror_port_stats(struct lan966x_port *port,
struct flow_stats *stats,
bool ingress)
{
struct rtnl_link_stats64 new_stats;
struct flow_stats *old_stats;
old_stats = &port->tc.mirror_stat;
lan966x_stats_get(port->dev, &new_stats);
if (ingress) {
flow_stats_update(stats,
new_stats.rx_bytes - old_stats->bytes,
new_stats.rx_packets - old_stats->pkts,
new_stats.rx_dropped - old_stats->drops,
old_stats->lastused,
FLOW_ACTION_HW_STATS_IMMEDIATE);
old_stats->bytes = new_stats.rx_bytes;
old_stats->pkts = new_stats.rx_packets;
old_stats->drops = new_stats.rx_dropped;
old_stats->lastused = jiffies;
} else {
flow_stats_update(stats,
new_stats.tx_bytes - old_stats->bytes,
new_stats.tx_packets - old_stats->pkts,
new_stats.tx_dropped - old_stats->drops,
old_stats->lastused,
FLOW_ACTION_HW_STATS_IMMEDIATE);
old_stats->bytes = new_stats.tx_bytes;
old_stats->pkts = new_stats.tx_packets;
old_stats->drops = new_stats.tx_dropped;
old_stats->lastused = jiffies;
}
}
// SPDX-License-Identifier: GPL-2.0+
#include "lan966x_main.h"
/* 0-8 : 9 port policers */
#define POL_IDX_PORT 0
/* Policer order: Serial (QoS -> Port -> VCAP) */
#define POL_ORDER 0x1d3
struct lan966x_tc_policer {
/* kilobit per second */
u32 rate;
/* bytes */
u32 burst;
};
static int lan966x_police_add(struct lan966x_port *port,
struct lan966x_tc_policer *pol,
u16 pol_idx)
{
struct lan966x *lan966x = port->lan966x;
/* Rate unit is 33 1/3 kpps */
pol->rate = DIV_ROUND_UP(pol->rate * 3, 100);
/* Avoid zero burst size */
pol->burst = pol->burst ?: 1;
/* Unit is 4kB */
pol->burst = DIV_ROUND_UP(pol->burst, 4096);
if (pol->rate > GENMASK(15, 0) ||
pol->burst > GENMASK(6, 0))
return -EINVAL;
lan_wr(ANA_POL_MODE_DROP_ON_YELLOW_ENA_SET(0) |
ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA_SET(0) |
ANA_POL_MODE_IPG_SIZE_SET(20) |
ANA_POL_MODE_FRM_MODE_SET(1) |
ANA_POL_MODE_OVERSHOOT_ENA_SET(1),
lan966x, ANA_POL_MODE(pol_idx));
lan_wr(ANA_POL_PIR_STATE_PIR_LVL_SET(0),
lan966x, ANA_POL_PIR_STATE(pol_idx));
lan_wr(ANA_POL_PIR_CFG_PIR_RATE_SET(pol->rate) |
ANA_POL_PIR_CFG_PIR_BURST_SET(pol->burst),
lan966x, ANA_POL_PIR_CFG(pol_idx));
return 0;
}
static int lan966x_police_del(struct lan966x_port *port,
u16 pol_idx)
{
struct lan966x *lan966x = port->lan966x;
lan_wr(ANA_POL_MODE_DROP_ON_YELLOW_ENA_SET(0) |
ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA_SET(0) |
ANA_POL_MODE_IPG_SIZE_SET(20) |
ANA_POL_MODE_FRM_MODE_SET(2) |
ANA_POL_MODE_OVERSHOOT_ENA_SET(1),
lan966x, ANA_POL_MODE(pol_idx));
lan_wr(ANA_POL_PIR_STATE_PIR_LVL_SET(0),
lan966x, ANA_POL_PIR_STATE(pol_idx));
lan_wr(ANA_POL_PIR_CFG_PIR_RATE_SET(GENMASK(14, 0)) |
ANA_POL_PIR_CFG_PIR_BURST_SET(0),
lan966x, ANA_POL_PIR_CFG(pol_idx));
return 0;
}
static int lan966x_police_validate(struct lan966x_port *port,
const struct flow_action *action,
const struct flow_action_entry *act,
unsigned long police_id,
bool ingress,
struct netlink_ext_ack *extack)
{
if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when exceed action is not drop");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is not pipe or ok");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
!flow_action_is_last_entry(action, act)) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is ok, but action is not last");
return -EOPNOTSUPP;
}
if (act->police.peakrate_bytes_ps ||
act->police.avrate || act->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
if (act->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack,
"QoS offload not support packets per second");
return -EOPNOTSUPP;
}
if (!ingress) {
NL_SET_ERR_MSG_MOD(extack,
"Policer is not supported on egress");
return -EOPNOTSUPP;
}
if (port->tc.ingress_shared_block) {
NL_SET_ERR_MSG_MOD(extack,
"Policer is not supported on shared ingress blocks");
return -EOPNOTSUPP;
}
if (port->tc.police_id && port->tc.police_id != police_id) {
NL_SET_ERR_MSG_MOD(extack,
"Only one policer per port is supported");
return -EEXIST;
}
return 0;
}
int lan966x_police_port_add(struct lan966x_port *port,
struct flow_action *action,
struct flow_action_entry *act,
unsigned long police_id,
bool ingress,
struct netlink_ext_ack *extack)
{
struct lan966x *lan966x = port->lan966x;
struct rtnl_link_stats64 new_stats;
struct lan966x_tc_policer pol;
struct flow_stats *old_stats;
int err;
err = lan966x_police_validate(port, action, act, police_id, ingress,
extack);
if (err)
return err;
memset(&pol, 0, sizeof(pol));
pol.rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
pol.burst = act->police.burst;
err = lan966x_police_add(port, &pol, POL_IDX_PORT + port->chip_port);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed to add policer to port");
return err;
}
lan_rmw(ANA_POL_CFG_PORT_POL_ENA_SET(1) |
ANA_POL_CFG_POL_ORDER_SET(POL_ORDER),
ANA_POL_CFG_PORT_POL_ENA |
ANA_POL_CFG_POL_ORDER,
lan966x, ANA_POL_CFG(port->chip_port));
port->tc.police_id = police_id;
/* Setup initial stats */
old_stats = &port->tc.police_stat;
lan966x_stats_get(port->dev, &new_stats);
old_stats->bytes = new_stats.rx_bytes;
old_stats->pkts = new_stats.rx_packets;
old_stats->drops = new_stats.rx_dropped;
old_stats->lastused = jiffies;
return 0;
}
int lan966x_police_port_del(struct lan966x_port *port,
unsigned long police_id,
struct netlink_ext_ack *extack)
{
struct lan966x *lan966x = port->lan966x;
int err;
if (port->tc.police_id != police_id) {
NL_SET_ERR_MSG_MOD(extack,
"Invalid policer id");
return -EINVAL;
}
err = lan966x_police_del(port, port->tc.police_id);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed to add policer to port");
return err;
}
lan_rmw(ANA_POL_CFG_PORT_POL_ENA_SET(0) |
ANA_POL_CFG_POL_ORDER_SET(POL_ORDER),
ANA_POL_CFG_PORT_POL_ENA |
ANA_POL_CFG_POL_ORDER,
lan966x, ANA_POL_CFG(port->chip_port));
port->tc.police_id = 0;
return 0;
}
void lan966x_police_port_stats(struct lan966x_port *port,
struct flow_stats *stats)
{
struct rtnl_link_stats64 new_stats;
struct flow_stats *old_stats;
old_stats = &port->tc.police_stat;
lan966x_stats_get(port->dev, &new_stats);
flow_stats_update(stats,
new_stats.rx_bytes - old_stats->bytes,
new_stats.rx_packets - old_stats->pkts,
new_stats.rx_dropped - old_stats->drops,
old_stats->lastused,
FLOW_ACTION_HW_STATS_IMMEDIATE);
old_stats->bytes = new_stats.rx_bytes;
old_stats->pkts = new_stats.rx_packets;
old_stats->drops = new_stats.rx_dropped;
old_stats->lastused = jiffies;
}
......@@ -90,6 +90,24 @@ enum lan966x_target {
#define ANA_AUTOAGE_AGE_PERIOD_GET(x)\
FIELD_GET(ANA_AUTOAGE_AGE_PERIOD, x)
/* ANA:ANA:MIRRORPORTS */
#define ANA_MIRRORPORTS __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 60, 0, 1, 4)
#define ANA_MIRRORPORTS_MIRRORPORTS GENMASK(8, 0)
#define ANA_MIRRORPORTS_MIRRORPORTS_SET(x)\
FIELD_PREP(ANA_MIRRORPORTS_MIRRORPORTS, x)
#define ANA_MIRRORPORTS_MIRRORPORTS_GET(x)\
FIELD_GET(ANA_MIRRORPORTS_MIRRORPORTS, x)
/* ANA:ANA:EMIRRORPORTS */
#define ANA_EMIRRORPORTS __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 64, 0, 1, 4)
#define ANA_EMIRRORPORTS_EMIRRORPORTS GENMASK(8, 0)
#define ANA_EMIRRORPORTS_EMIRRORPORTS_SET(x)\
FIELD_PREP(ANA_EMIRRORPORTS_EMIRRORPORTS, x)
#define ANA_EMIRRORPORTS_EMIRRORPORTS_GET(x)\
FIELD_GET(ANA_EMIRRORPORTS_EMIRRORPORTS, x)
/* ANA:ANA:FLOODING */
#define ANA_FLOODING(r) __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 68, r, 8, 4)
......@@ -330,6 +348,12 @@ enum lan966x_target {
/* ANA:PORT:PORT_CFG */
#define ANA_PORT_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 112, 0, 1, 4)
#define ANA_PORT_CFG_SRC_MIRROR_ENA BIT(13)
#define ANA_PORT_CFG_SRC_MIRROR_ENA_SET(x)\
FIELD_PREP(ANA_PORT_CFG_SRC_MIRROR_ENA, x)
#define ANA_PORT_CFG_SRC_MIRROR_ENA_GET(x)\
FIELD_GET(ANA_PORT_CFG_SRC_MIRROR_ENA, x)
#define ANA_PORT_CFG_LEARNAUTO BIT(6)
#define ANA_PORT_CFG_LEARNAUTO_SET(x)\
FIELD_PREP(ANA_PORT_CFG_LEARNAUTO, x)
......@@ -354,6 +378,21 @@ enum lan966x_target {
#define ANA_PORT_CFG_PORTID_VAL_GET(x)\
FIELD_GET(ANA_PORT_CFG_PORTID_VAL, x)
/* ANA:PORT:POL_CFG */
#define ANA_POL_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 116, 0, 1, 4)
#define ANA_POL_CFG_PORT_POL_ENA BIT(17)
#define ANA_POL_CFG_PORT_POL_ENA_SET(x)\
FIELD_PREP(ANA_POL_CFG_PORT_POL_ENA, x)
#define ANA_POL_CFG_PORT_POL_ENA_GET(x)\
FIELD_GET(ANA_POL_CFG_PORT_POL_ENA, x)
#define ANA_POL_CFG_POL_ORDER GENMASK(8, 0)
#define ANA_POL_CFG_POL_ORDER_SET(x)\
FIELD_PREP(ANA_POL_CFG_POL_ORDER, x)
#define ANA_POL_CFG_POL_ORDER_GET(x)\
FIELD_GET(ANA_POL_CFG_POL_ORDER, x)
/* ANA:PFC:PFC_CFG */
#define ANA_PFC_CFG(g) __REG(TARGET_ANA, 0, 1, 30720, g, 8, 64, 0, 0, 1, 4)
......@@ -408,6 +447,63 @@ enum lan966x_target {
#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA_GET(x)\
FIELD_GET(ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA, x)
/* ANA:POL:POL_PIR_CFG */
#define ANA_POL_PIR_CFG(g) __REG(TARGET_ANA, 0, 1, 16384, g, 345, 32, 0, 0, 1, 4)
#define ANA_POL_PIR_CFG_PIR_RATE GENMASK(20, 6)
#define ANA_POL_PIR_CFG_PIR_RATE_SET(x)\
FIELD_PREP(ANA_POL_PIR_CFG_PIR_RATE, x)
#define ANA_POL_PIR_CFG_PIR_RATE_GET(x)\
FIELD_GET(ANA_POL_PIR_CFG_PIR_RATE, x)
#define ANA_POL_PIR_CFG_PIR_BURST GENMASK(5, 0)
#define ANA_POL_PIR_CFG_PIR_BURST_SET(x)\
FIELD_PREP(ANA_POL_PIR_CFG_PIR_BURST, x)
#define ANA_POL_PIR_CFG_PIR_BURST_GET(x)\
FIELD_GET(ANA_POL_PIR_CFG_PIR_BURST, x)
/* ANA:POL:POL_MODE_CFG */
#define ANA_POL_MODE(g) __REG(TARGET_ANA, 0, 1, 16384, g, 345, 32, 8, 0, 1, 4)
#define ANA_POL_MODE_DROP_ON_YELLOW_ENA BIT(11)
#define ANA_POL_MODE_DROP_ON_YELLOW_ENA_SET(x)\
FIELD_PREP(ANA_POL_MODE_DROP_ON_YELLOW_ENA, x)
#define ANA_POL_MODE_DROP_ON_YELLOW_ENA_GET(x)\
FIELD_GET(ANA_POL_MODE_DROP_ON_YELLOW_ENA, x)
#define ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA BIT(10)
#define ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA_SET(x)\
FIELD_PREP(ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA, x)
#define ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA_GET(x)\
FIELD_GET(ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA, x)
#define ANA_POL_MODE_IPG_SIZE GENMASK(9, 5)
#define ANA_POL_MODE_IPG_SIZE_SET(x)\
FIELD_PREP(ANA_POL_MODE_IPG_SIZE, x)
#define ANA_POL_MODE_IPG_SIZE_GET(x)\
FIELD_GET(ANA_POL_MODE_IPG_SIZE, x)
#define ANA_POL_MODE_FRM_MODE GENMASK(4, 3)
#define ANA_POL_MODE_FRM_MODE_SET(x)\
FIELD_PREP(ANA_POL_MODE_FRM_MODE, x)
#define ANA_POL_MODE_FRM_MODE_GET(x)\
FIELD_GET(ANA_POL_MODE_FRM_MODE, x)
#define ANA_POL_MODE_OVERSHOOT_ENA BIT(0)
#define ANA_POL_MODE_OVERSHOOT_ENA_SET(x)\
FIELD_PREP(ANA_POL_MODE_OVERSHOOT_ENA, x)
#define ANA_POL_MODE_OVERSHOOT_ENA_GET(x)\
FIELD_GET(ANA_POL_MODE_OVERSHOOT_ENA, x)
/* ANA:POL:POL_PIR_STATE */
#define ANA_POL_PIR_STATE(g) __REG(TARGET_ANA, 0, 1, 16384, g, 345, 32, 12, 0, 1, 4)
#define ANA_POL_PIR_STATE_PIR_LVL GENMASK(21, 0)
#define ANA_POL_PIR_STATE_PIR_LVL_SET(x)\
FIELD_PREP(ANA_POL_PIR_STATE_PIR_LVL, x)
#define ANA_POL_PIR_STATE_PIR_LVL_GET(x)\
FIELD_GET(ANA_POL_PIR_STATE_PIR_LVL, x)
/* CHIP_TOP:CUPHY_CFG:CUPHY_PORT_CFG */
#define CHIP_TOP_CUPHY_PORT_CFG(r) __REG(TARGET_CHIP_TOP, 0, 1, 16, 0, 1, 20, 8, r, 2, 4)
......
......@@ -4,6 +4,8 @@
#include "lan966x_main.h"
static LIST_HEAD(lan966x_tc_block_cb_list);
static int lan966x_tc_setup_qdisc_mqprio(struct lan966x_port *port,
struct tc_mqprio_qopt_offload *mqprio)
{
......@@ -59,6 +61,52 @@ static int lan966x_tc_setup_qdisc_ets(struct lan966x_port *port,
return -EOPNOTSUPP;
}
static int lan966x_tc_block_cb(enum tc_setup_type type, void *type_data,
void *cb_priv, bool ingress)
{
struct lan966x_port *port = cb_priv;
switch (type) {
case TC_SETUP_CLSMATCHALL:
return lan966x_tc_matchall(port, type_data, ingress);
default:
return -EOPNOTSUPP;
}
}
static int lan966x_tc_block_cb_ingress(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
return lan966x_tc_block_cb(type, type_data, cb_priv, true);
}
static int lan966x_tc_block_cb_egress(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
return lan966x_tc_block_cb(type, type_data, cb_priv, false);
}
static int lan966x_tc_setup_block(struct lan966x_port *port,
struct flow_block_offload *f)
{
flow_setup_cb_t *cb;
bool ingress;
if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = lan966x_tc_block_cb_ingress;
port->tc.ingress_shared_block = f->block_shared;
ingress = true;
} else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
cb = lan966x_tc_block_cb_egress;
ingress = false;
} else {
return -EOPNOTSUPP;
}
return flow_block_cb_setup_simple(f, &lan966x_tc_block_cb_list,
cb, port, port, ingress);
}
int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
......@@ -75,6 +123,8 @@ int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type,
return lan966x_tc_setup_qdisc_cbs(port, type_data);
case TC_SETUP_QDISC_ETS:
return lan966x_tc_setup_qdisc_ets(port, type_data);
case TC_SETUP_BLOCK:
return lan966x_tc_setup_block(port, type_data);
default:
return -EOPNOTSUPP;
}
......
// SPDX-License-Identifier: GPL-2.0+
#include "lan966x_main.h"
static int lan966x_tc_matchall_add(struct lan966x_port *port,
struct tc_cls_matchall_offload *f,
bool ingress)
{
struct flow_action_entry *act;
if (!flow_offload_has_one_action(&f->rule->action)) {
NL_SET_ERR_MSG_MOD(f->common.extack,
"Only once action per filter is supported");
return -EOPNOTSUPP;
}
act = &f->rule->action.entries[0];
switch (act->id) {
case FLOW_ACTION_POLICE:
return lan966x_police_port_add(port, &f->rule->action, act,
f->cookie, ingress,
f->common.extack);
case FLOW_ACTION_MIRRED:
return lan966x_mirror_port_add(port, act, f->cookie,
ingress, f->common.extack);
default:
NL_SET_ERR_MSG_MOD(f->common.extack,
"Unsupported action");
return -EOPNOTSUPP;
}
return 0;
}
static int lan966x_tc_matchall_del(struct lan966x_port *port,
struct tc_cls_matchall_offload *f,
bool ingress)
{
if (f->cookie == port->tc.police_id) {
return lan966x_police_port_del(port, f->cookie,
f->common.extack);
} else if (f->cookie == port->tc.ingress_mirror_id ||
f->cookie == port->tc.egress_mirror_id) {
return lan966x_mirror_port_del(port, ingress,
f->common.extack);
} else {
NL_SET_ERR_MSG_MOD(f->common.extack,
"Unsupported action");
return -EOPNOTSUPP;
}
return 0;
}
static int lan966x_tc_matchall_stats(struct lan966x_port *port,
struct tc_cls_matchall_offload *f,
bool ingress)
{
if (f->cookie == port->tc.police_id) {
lan966x_police_port_stats(port, &f->stats);
} else if (f->cookie == port->tc.ingress_mirror_id ||
f->cookie == port->tc.egress_mirror_id) {
lan966x_mirror_port_stats(port, &f->stats, ingress);
} else {
NL_SET_ERR_MSG_MOD(f->common.extack,
"Unsupported action");
return -EOPNOTSUPP;
}
return 0;
}
int lan966x_tc_matchall(struct lan966x_port *port,
struct tc_cls_matchall_offload *f,
bool ingress)
{
if (!tc_cls_can_offload_and_chain0(port->dev, &f->common)) {
NL_SET_ERR_MSG_MOD(f->common.extack,
"Only chain zero is supported");
return -EOPNOTSUPP;
}
switch (f->command) {
case TC_CLSMATCHALL_REPLACE:
return lan966x_tc_matchall_add(port, f, ingress);
case TC_CLSMATCHALL_DESTROY:
return lan966x_tc_matchall_del(port, f, ingress);
case TC_CLSMATCHALL_STATS:
return lan966x_tc_matchall_stats(port, f, ingress);
default:
return -EOPNOTSUPP;
}
return 0;
}
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