Commit 3a972364 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-spectrum-Implement-loopback-ethtool-feature'

Ido Schimmel says:

====================
mlxsw: spectrum: Implement loopback ethtool feature

This patchset from Jiri allows users to enable loopback feature for
individual ports using ethtool. The loopback feature is useful for
testing purposes and will also be used by upcoming patchsets to enable
the monitoring of buffer drops.

Patch #1 adds the relevant device register.

Patch #2 Implements support in the driver.

Patch #3 adds a selftest.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b362487a ad113409
......@@ -5210,6 +5210,42 @@ static inline void mlxsw_reg_pspa_pack(char *payload, u8 swid, u8 local_port)
mlxsw_reg_pspa_sub_port_set(payload, 0);
}
/* PPLR - Port Physical Loopback Register
* --------------------------------------
* This register allows configuration of the port's loopback mode.
*/
#define MLXSW_REG_PPLR_ID 0x5018
#define MLXSW_REG_PPLR_LEN 0x8
MLXSW_REG_DEFINE(pplr, MLXSW_REG_PPLR_ID, MLXSW_REG_PPLR_LEN);
/* reg_pplr_local_port
* Local port number.
* Access: Index
*/
MLXSW_ITEM32(reg, pplr, local_port, 0x00, 16, 8);
/* Phy local loopback. When set the port's egress traffic is looped back
* to the receiver and the port transmitter is disabled.
*/
#define MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL BIT(1)
/* reg_pplr_lb_en
* Loopback enable.
* Access: RW
*/
MLXSW_ITEM32(reg, pplr, lb_en, 0x04, 0, 8);
static inline void mlxsw_reg_pplr_pack(char *payload, u8 local_port,
bool phy_local)
{
MLXSW_REG_ZERO(pplr, payload);
mlxsw_reg_pplr_local_port_set(payload, local_port);
mlxsw_reg_pplr_lb_en_set(payload,
phy_local ?
MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL : 0);
}
/* HTGT - Host Trap Group Table
* ----------------------------
* Configures the properties for forwarding to CPU.
......@@ -9981,6 +10017,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(pptb),
MLXSW_REG(pbmc),
MLXSW_REG(pspa),
MLXSW_REG(pplr),
MLXSW_REG(htgt),
MLXSW_REG(hpkt),
MLXSW_REG(rgcr),
......
......@@ -1669,6 +1669,25 @@ static int mlxsw_sp_feature_hw_tc(struct net_device *dev, bool enable)
return 0;
}
static int mlxsw_sp_feature_loopback(struct net_device *dev, bool enable)
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
char pplr_pl[MLXSW_REG_PPLR_LEN];
int err;
if (netif_running(dev))
mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
mlxsw_reg_pplr_pack(pplr_pl, mlxsw_sp_port->local_port, enable);
err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pplr),
pplr_pl);
if (netif_running(dev))
mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
return err;
}
typedef int (*mlxsw_sp_feature_handler)(struct net_device *dev, bool enable);
static int mlxsw_sp_handle_feature(struct net_device *dev,
......@@ -1700,8 +1719,20 @@ static int mlxsw_sp_handle_feature(struct net_device *dev,
static int mlxsw_sp_set_features(struct net_device *dev,
netdev_features_t features)
{
return mlxsw_sp_handle_feature(dev, features, NETIF_F_HW_TC,
netdev_features_t oper_features = dev->features;
int err = 0;
err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_HW_TC,
mlxsw_sp_feature_hw_tc);
err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_LOOPBACK,
mlxsw_sp_feature_loopback);
if (err) {
dev->features = oper_features;
return -EINVAL;
}
return 0;
}
static struct devlink_port *
......@@ -3452,7 +3483,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_LLTX | NETIF_F_SG |
NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
dev->hw_features |= NETIF_F_HW_TC;
dev->hw_features |= NETIF_F_HW_TC | NETIF_F_LOOPBACK;
dev->min_mtu = 0;
dev->max_mtu = ETH_MAX_MTU;
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
ALL_TESTS="loopback_test"
NUM_NETIFS=2
source tc_common.sh
source lib.sh
h1_create()
{
simple_if_init $h1 192.0.2.1/24
tc qdisc add dev $h1 clsact
}
h1_destroy()
{
tc qdisc del dev $h1 clsact
simple_if_fini $h1 192.0.2.1/24
}
h2_create()
{
simple_if_init $h2
}
h2_destroy()
{
simple_if_fini $h2
}
loopback_test()
{
RET=0
tc filter add dev $h1 ingress protocol arp pref 1 handle 101 flower \
skip_hw arp_op reply arp_tip 192.0.2.1 action drop
$MZ $h1 -c 1 -t arp -q
tc_check_packets "dev $h1 ingress" 101 1
check_fail $? "Matched on a filter without loopback setup"
ethtool -K $h1 loopback on
check_err $? "Failed to enable loopback"
setup_wait_dev $h1
$MZ $h1 -c 1 -t arp -q
tc_check_packets "dev $h1 ingress" 101 1
check_err $? "Did not match on filter with loopback"
ethtool -K $h1 loopback off
check_err $? "Failed to disable loopback"
$MZ $h1 -c 1 -t arp -q
tc_check_packets "dev $h1 ingress" 101 2
check_fail $? "Matched on a filter after loopback was removed"
tc filter del dev $h1 ingress protocol arp pref 1 handle 101 flower
log_test "loopback"
}
setup_prepare()
{
h1=${NETIFS[p1]}
h2=${NETIFS[p2]}
vrf_prepare
h1_create
h2_create
}
cleanup()
{
pre_cleanup
h2_destroy
h1_destroy
vrf_cleanup
}
trap cleanup EXIT
setup_prepare
setup_wait
tests_run
exit $EXIT_STATUS
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