diff options
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfd3/rings.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfdk/rings.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 71 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 167 |
5 files changed, 240 insertions, 2 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfd3/rings.c b/drivers/net/ethernet/netronome/nfp/nfd3/rings.c index f31eabdc0631..f65851ed5b50 100644 --- a/drivers/net/ethernet/netronome/nfp/nfd3/rings.c +++ b/drivers/net/ethernet/netronome/nfp/nfd3/rings.c @@ -251,6 +251,7 @@ nfp_nfd3_print_tx_descs(struct seq_file *file, NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA | \ NFP_NET_CFG_CTRL_RINGCFG | NFP_NET_CFG_CTRL_RSS | \ NFP_NET_CFG_CTRL_IRQMOD | NFP_NET_CFG_CTRL_TXRWB | \ + NFP_NET_CFG_CTRL_VEPA | \ NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE | \ NFP_NET_CFG_CTRL_BPF | NFP_NET_CFG_CTRL_LSO2 | \ NFP_NET_CFG_CTRL_RSS2 | NFP_NET_CFG_CTRL_CSUM_COMPLETE | \ diff --git a/drivers/net/ethernet/netronome/nfp/nfdk/rings.c b/drivers/net/ethernet/netronome/nfp/nfdk/rings.c index f4d94ae0a349..222ee0e5302f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfdk/rings.c +++ b/drivers/net/ethernet/netronome/nfp/nfdk/rings.c @@ -171,7 +171,7 @@ nfp_nfdk_print_tx_descs(struct seq_file *file, NFP_NET_CFG_CTRL_GATHER | NFP_NET_CFG_CTRL_LSO | \ NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA | \ NFP_NET_CFG_CTRL_RINGCFG | NFP_NET_CFG_CTRL_IRQMOD | \ - NFP_NET_CFG_CTRL_TXRWB | \ + NFP_NET_CFG_CTRL_TXRWB | NFP_NET_CFG_CTRL_VEPA | \ NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE | \ NFP_NET_CFG_CTRL_BPF | NFP_NET_CFG_CTRL_LSO2 | \ NFP_NET_CFG_CTRL_RSS2 | NFP_NET_CFG_CTRL_CSUM_COMPLETE | \ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 57f284eefeb3..0991fc122998 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -31,6 +31,7 @@ #include <linux/ethtool.h> #include <linux/log2.h> #include <linux/if_vlan.h> +#include <linux/if_bridge.h> #include <linux/random.h> #include <linux/vmalloc.h> #include <linux/ktime.h> @@ -1892,6 +1893,69 @@ static int nfp_net_set_mac_address(struct net_device *netdev, void *addr) return 0; } +static int nfp_net_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, + struct net_device *dev, u32 filter_mask, + int nlflags) +{ + struct nfp_net *nn = netdev_priv(dev); + u16 mode; + + if (!(nn->cap & NFP_NET_CFG_CTRL_VEPA)) + return -EOPNOTSUPP; + + mode = (nn->dp.ctrl & NFP_NET_CFG_CTRL_VEPA) ? + BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB; + + return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, 0, 0, + nlflags, filter_mask, NULL); +} + +static int nfp_net_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, + u16 flags, struct netlink_ext_ack *extack) +{ + struct nfp_net *nn = netdev_priv(dev); + struct nlattr *attr, *br_spec; + int rem, err; + u32 new_ctrl; + u16 mode; + + if (!(nn->cap & NFP_NET_CFG_CTRL_VEPA)) + return -EOPNOTSUPP; + + br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); + if (!br_spec) + return -EINVAL; + + nla_for_each_nested(attr, br_spec, rem) { + if (nla_type(attr) != IFLA_BRIDGE_MODE) + continue; + + if (nla_len(attr) < sizeof(mode)) + return -EINVAL; + + new_ctrl = nn->dp.ctrl; + mode = nla_get_u16(attr); + if (mode == BRIDGE_MODE_VEPA) + new_ctrl |= NFP_NET_CFG_CTRL_VEPA; + else if (mode == BRIDGE_MODE_VEB) + new_ctrl &= ~NFP_NET_CFG_CTRL_VEPA; + else + return -EOPNOTSUPP; + + if (new_ctrl == nn->dp.ctrl) + return 0; + + nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl); + err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); + if (!err) + nn->dp.ctrl = new_ctrl; + + return err; + } + + return -EINVAL; +} + const struct net_device_ops nfp_nfd3_netdev_ops = { .ndo_init = nfp_app_ndo_init, .ndo_uninit = nfp_app_ndo_uninit, @@ -1919,6 +1983,8 @@ const struct net_device_ops nfp_nfd3_netdev_ops = { .ndo_bpf = nfp_net_xdp, .ndo_xsk_wakeup = nfp_net_xsk_wakeup, .ndo_get_devlink_port = nfp_devlink_get_devlink_port, + .ndo_bridge_getlink = nfp_net_bridge_getlink, + .ndo_bridge_setlink = nfp_net_bridge_setlink, }; const struct net_device_ops nfp_nfdk_netdev_ops = { @@ -1946,6 +2012,8 @@ const struct net_device_ops nfp_nfdk_netdev_ops = { .ndo_get_phys_port_name = nfp_net_get_phys_port_name, .ndo_bpf = nfp_net_xdp, .ndo_get_devlink_port = nfp_devlink_get_devlink_port, + .ndo_bridge_getlink = nfp_net_bridge_getlink, + .ndo_bridge_setlink = nfp_net_bridge_setlink, }; static int nfp_udp_tunnel_sync(struct net_device *netdev, unsigned int table) @@ -1993,7 +2061,7 @@ void nfp_net_info(struct nfp_net *nn) nn->fw_ver.extend, nn->fw_ver.class, nn->fw_ver.major, nn->fw_ver.minor, nn->max_mtu); - nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", nn->cap, nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "", nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "", @@ -2012,6 +2080,7 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_MSIXAUTO ? "AUTOMASK " : "", nn->cap & NFP_NET_CFG_CTRL_IRQMOD ? "IRQMOD " : "", nn->cap & NFP_NET_CFG_CTRL_TXRWB ? "TXRWB " : "", + nn->cap & NFP_NET_CFG_CTRL_VEPA ? "VEPA " : "", nn->cap & NFP_NET_CFG_CTRL_VXLAN ? "VXLAN " : "", nn->cap & NFP_NET_CFG_CTRL_NVGRE ? "NVGRE " : "", nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ? diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 8892a94f00c3..9007675db67f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -94,6 +94,7 @@ #define NFP_NET_CFG_CTRL_IRQMOD (0x1 << 18) /* Interrupt moderation */ #define NFP_NET_CFG_CTRL_MSIXAUTO (0x1 << 20) /* MSI-X auto-masking */ #define NFP_NET_CFG_CTRL_TXRWB (0x1 << 21) /* Write-back of TX ring*/ +#define NFP_NET_CFG_CTRL_VEPA (0x1 << 22) /* Enable VEPA mode */ #define NFP_NET_CFG_CTRL_VXLAN (0x1 << 24) /* VXLAN tunnel support */ #define NFP_NET_CFG_CTRL_NVGRE (0x1 << 25) /* NVGRE tunnel support */ #define NFP_NET_CFG_CTRL_BPF (0x1 << 27) /* BPF offload capable */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 7475b209353f..c922dfab8080 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -29,6 +29,7 @@ #include "nfp_net_dp.h" #include "nfp_net.h" #include "nfp_port.h" +#include "nfpcore/nfp_cpp.h" struct nfp_et_stat { char name[ETH_GSTRING_LEN]; @@ -442,6 +443,160 @@ static int nfp_net_set_ringparam(struct net_device *netdev, return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt); } +static int nfp_test_link(struct net_device *netdev) +{ + if (!netif_carrier_ok(netdev) || !(netdev->flags & IFF_UP)) + return 1; + + return 0; +} + +static int nfp_test_nsp(struct net_device *netdev) +{ + struct nfp_app *app = nfp_app_from_netdev(netdev); + struct nfp_nsp_identify *nspi; + struct nfp_nsp *nsp; + int err; + + nsp = nfp_nsp_open(app->cpp); + if (IS_ERR(nsp)) { + err = PTR_ERR(nsp); + netdev_info(netdev, "NSP Test: failed to access the NSP: %d\n", err); + goto exit; + } + + if (nfp_nsp_get_abi_ver_minor(nsp) < 15) { + err = -EOPNOTSUPP; + goto exit_close_nsp; + } + + nspi = kzalloc(sizeof(*nspi), GFP_KERNEL); + if (!nspi) { + err = -ENOMEM; + goto exit_close_nsp; + } + + err = nfp_nsp_read_identify(nsp, nspi, sizeof(*nspi)); + if (err < 0) + netdev_info(netdev, "NSP Test: reading bsp version failed %d\n", err); + + kfree(nspi); +exit_close_nsp: + nfp_nsp_close(nsp); +exit: + return err; +} + +static int nfp_test_fw(struct net_device *netdev) +{ + struct nfp_net *nn = netdev_priv(netdev); + int err; + + err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); + if (err) + netdev_info(netdev, "FW Test: update failed %d\n", err); + + return err; +} + +static int nfp_test_reg(struct net_device *netdev) +{ + struct nfp_app *app = nfp_app_from_netdev(netdev); + struct nfp_cpp *cpp = app->cpp; + u32 model = nfp_cpp_model(cpp); + u32 value; + int err; + + err = nfp_cpp_model_autodetect(cpp, &value); + if (err < 0) { + netdev_info(netdev, "REG Test: NFP model detection failed %d\n", err); + return err; + } + + return (value == model) ? 0 : 1; +} + +static bool link_test_supported(struct net_device *netdev) +{ + return true; +} + +static bool nsp_test_supported(struct net_device *netdev) +{ + if (nfp_app_from_netdev(netdev)) + return true; + + return false; +} + +static bool fw_test_supported(struct net_device *netdev) +{ + if (nfp_netdev_is_nfp_net(netdev)) + return true; + + return false; +} + +static bool reg_test_supported(struct net_device *netdev) +{ + if (nfp_app_from_netdev(netdev)) + return true; + + return false; +} + +static struct nfp_self_test_item { + char name[ETH_GSTRING_LEN]; + bool (*is_supported)(struct net_device *dev); + int (*func)(struct net_device *dev); +} nfp_self_test[] = { + {"Link Test", link_test_supported, nfp_test_link}, + {"NSP Test", nsp_test_supported, nfp_test_nsp}, + {"Firmware Test", fw_test_supported, nfp_test_fw}, + {"Register Test", reg_test_supported, nfp_test_reg} +}; + +#define NFP_TEST_TOTAL_NUM ARRAY_SIZE(nfp_self_test) + +static void nfp_get_self_test_strings(struct net_device *netdev, u8 *data) +{ + int i; + + for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) + if (nfp_self_test[i].is_supported(netdev)) + ethtool_sprintf(&data, nfp_self_test[i].name); +} + +static int nfp_get_self_test_count(struct net_device *netdev) +{ + int i, count = 0; + + for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) + if (nfp_self_test[i].is_supported(netdev)) + count++; + + return count; +} + +static void nfp_net_self_test(struct net_device *netdev, struct ethtool_test *eth_test, + u64 *data) +{ + int i, ret, count = 0; + + netdev_info(netdev, "Start self test\n"); + + for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) { + if (nfp_self_test[i].is_supported(netdev)) { + ret = nfp_self_test[i].func(netdev); + if (ret) + eth_test->flags |= ETH_TEST_FL_FAILED; + data[count++] = ret; + } + } + + netdev_info(netdev, "Test end\n"); +} + static unsigned int nfp_vnic_get_sw_stats_count(struct net_device *netdev) { struct nfp_net *nn = netdev_priv(netdev); @@ -705,6 +860,9 @@ static void nfp_net_get_strings(struct net_device *netdev, data = nfp_mac_get_stats_strings(netdev, data); data = nfp_app_port_get_stats_strings(nn->port, data); break; + case ETH_SS_TEST: + nfp_get_self_test_strings(netdev, data); + break; } } @@ -739,6 +897,8 @@ static int nfp_net_get_sset_count(struct net_device *netdev, int sset) cnt += nfp_mac_get_stats_count(netdev); cnt += nfp_app_port_get_stats_count(nn->port); return cnt; + case ETH_SS_TEST: + return nfp_get_self_test_count(netdev); default: return -EOPNOTSUPP; } @@ -757,6 +917,9 @@ static void nfp_port_get_strings(struct net_device *netdev, data = nfp_mac_get_stats_strings(netdev, data); data = nfp_app_port_get_stats_strings(port, data); break; + case ETH_SS_TEST: + nfp_get_self_test_strings(netdev, data); + break; } } @@ -786,6 +949,8 @@ static int nfp_port_get_sset_count(struct net_device *netdev, int sset) count = nfp_mac_get_stats_count(netdev); count += nfp_app_port_get_stats_count(port); return count; + case ETH_SS_TEST: + return nfp_get_self_test_count(netdev); default: return -EOPNOTSUPP; } @@ -1517,6 +1682,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { .get_link = ethtool_op_get_link, .get_ringparam = nfp_net_get_ringparam, .set_ringparam = nfp_net_set_ringparam, + .self_test = nfp_net_self_test, .get_strings = nfp_net_get_strings, .get_ethtool_stats = nfp_net_get_stats, .get_sset_count = nfp_net_get_sset_count, @@ -1550,6 +1716,7 @@ const struct ethtool_ops nfp_port_ethtool_ops = { .get_link = ethtool_op_get_link, .get_strings = nfp_port_get_strings, .get_ethtool_stats = nfp_port_get_stats, + .self_test = nfp_net_self_test, .get_sset_count = nfp_port_get_sset_count, .set_dump = nfp_app_set_dump, .get_dump_flag = nfp_app_get_dump_flag, |