Skip to content

Commit

Permalink
Merge branch 'nfp-vlan-strip-and-insert'
Browse files Browse the repository at this point in the history
Simon Horman says:

====================
nfp: support VLAN strip and insert

this series adds support to the NFP driver for HW offload of both:

* RX VLAN ctag/stag strip
* TX VLAN ctag insert
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 4, 2022
2 parents 5ee4bba + d80702f commit fd4b96c
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 40 deletions.
63 changes: 46 additions & 17 deletions drivers/net/ethernet/netronome/nfp/nfd3/dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <linux/bpf_trace.h>
#include <linux/netdevice.h>
#include <linux/bitfield.h>

#include "../nfp_app.h"
#include "../nfp_net.h"
Expand Down Expand Up @@ -166,44 +167,59 @@ nfp_nfd3_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
u64_stats_update_end(&r_vec->tx_sync);
}

static int nfp_nfd3_prep_tx_meta(struct sk_buff *skb, u64 tls_handle)
static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb, u64 tls_handle)
{
struct metadata_dst *md_dst = skb_metadata_dst(skb);
unsigned char *data;
bool vlan_insert;
u32 meta_id = 0;
int md_bytes;

if (likely(!md_dst && !tls_handle))
return 0;
if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX)) {
if (!tls_handle)
return 0;
md_dst = NULL;
if (unlikely(md_dst || tls_handle)) {
if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX))
md_dst = NULL;
}

md_bytes = 4 + !!md_dst * 4 + !!tls_handle * 8;
vlan_insert = skb_vlan_tag_present(skb) && (dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2);

if (!(md_dst || tls_handle || vlan_insert))
return 0;

md_bytes = sizeof(meta_id) +
!!md_dst * NFP_NET_META_PORTID_SIZE +
!!tls_handle * NFP_NET_META_CONN_HANDLE_SIZE +
vlan_insert * NFP_NET_META_VLAN_SIZE;

if (unlikely(skb_cow_head(skb, md_bytes)))
return -ENOMEM;

meta_id = 0;
data = skb_push(skb, md_bytes) + md_bytes;
if (md_dst) {
data -= 4;
data -= NFP_NET_META_PORTID_SIZE;
put_unaligned_be32(md_dst->u.port_info.port_id, data);
meta_id = NFP_NET_META_PORTID;
}
if (tls_handle) {
/* conn handle is opaque, we just use u64 to be able to quickly
* compare it to zero
*/
data -= 8;
data -= NFP_NET_META_CONN_HANDLE_SIZE;
memcpy(data, &tls_handle, sizeof(tls_handle));
meta_id <<= NFP_NET_META_FIELD_SIZE;
meta_id |= NFP_NET_META_CONN_HANDLE;
}
if (vlan_insert) {
data -= NFP_NET_META_VLAN_SIZE;
/* data type of skb->vlan_proto is __be16
* so it fills metadata without calling put_unaligned_be16
*/
memcpy(data, &skb->vlan_proto, sizeof(skb->vlan_proto));
put_unaligned_be16(skb_vlan_tag_get(skb), data + sizeof(skb->vlan_proto));
meta_id <<= NFP_NET_META_FIELD_SIZE;
meta_id |= NFP_NET_META_VLAN;
}

data -= 4;
data -= sizeof(meta_id);
put_unaligned_be32(meta_id, data);

return md_bytes;
Expand Down Expand Up @@ -257,7 +273,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}

md_bytes = nfp_nfd3_prep_tx_meta(skb, tls_handle);
md_bytes = nfp_nfd3_prep_tx_meta(dp, skb, tls_handle);
if (unlikely(md_bytes < 0))
goto err_flush;

Expand Down Expand Up @@ -703,7 +719,7 @@ bool
nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
void *data, void *pkt, unsigned int pkt_len, int meta_len)
{
u32 meta_info;
u32 meta_info, vlan_info;

meta_info = get_unaligned_be32(data);
data += 4;
Expand All @@ -721,6 +737,17 @@ nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
meta->mark = get_unaligned_be32(data);
data += 4;
break;
case NFP_NET_META_VLAN:
vlan_info = get_unaligned_be32(data);
if (FIELD_GET(NFP_NET_META_VLAN_STRIP, vlan_info)) {
meta->vlan.stripped = true;
meta->vlan.tpid = FIELD_GET(NFP_NET_META_VLAN_TPID_MASK,
vlan_info);
meta->vlan.tci = FIELD_GET(NFP_NET_META_VLAN_TCI_MASK,
vlan_info);
}
data += 4;
break;
case NFP_NET_META_PORTID:
meta->portid = get_unaligned_be32(data);
data += 4;
Expand Down Expand Up @@ -1049,9 +1076,11 @@ static int nfp_nfd3_rx(struct nfp_net_rx_ring *rx_ring, int budget)
}
#endif

if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
le16_to_cpu(rxd->rxd.vlan));
if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) {
nfp_nfd3_rx_drop(dp, r_vec, rx_ring, NULL, skb);
continue;
}

if (meta_len_xdp)
skb_metadata_set(skb, meta_len_xdp);

Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/netronome/nfp/nfd3/rings.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ nfp_nfd3_print_tx_descs(struct seq_file *file,
NFP_NET_CFG_CTRL_L2BC | NFP_NET_CFG_CTRL_L2MC | \
NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM | \
NFP_NET_CFG_CTRL_RXVLAN | NFP_NET_CFG_CTRL_TXVLAN | \
NFP_NET_CFG_CTRL_RXVLAN_V2 | NFP_NET_CFG_CTRL_RXQINQ | \
NFP_NET_CFG_CTRL_TXVLAN_V2 | \
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_RSS | \
Expand Down
9 changes: 6 additions & 3 deletions drivers/net/ethernet/netronome/nfp/nfd3/xsk.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,12 @@ static void nfp_nfd3_xsk_rx_skb(struct nfp_net_rx_ring *rx_ring,

nfp_nfd3_rx_csum(dp, r_vec, rxd, meta, skb);

if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
le16_to_cpu(rxd->rxd.vlan));
if (unlikely(!nfp_net_vlan_strip(skb, rxd, meta))) {
dev_kfree_skb_any(skb);
nfp_net_xsk_rx_drop(r_vec, xrxbuf);
return;
}

if (meta_xdp)
skb_metadata_set(skb,
xrxbuf->xdp->data - xrxbuf->xdp->data_meta);
Expand Down
21 changes: 17 additions & 4 deletions drivers/net/ethernet/netronome/nfp/nfdk/dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ static bool
nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
void *data, void *pkt, unsigned int pkt_len, int meta_len)
{
u32 meta_info;
u32 meta_info, vlan_info;

meta_info = get_unaligned_be32(data);
data += 4;
Expand All @@ -734,6 +734,17 @@ nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
meta->mark = get_unaligned_be32(data);
data += 4;
break;
case NFP_NET_META_VLAN:
vlan_info = get_unaligned_be32(data);
if (FIELD_GET(NFP_NET_META_VLAN_STRIP, vlan_info)) {
meta->vlan.stripped = true;
meta->vlan.tpid = FIELD_GET(NFP_NET_META_VLAN_TPID_MASK,
vlan_info);
meta->vlan.tci = FIELD_GET(NFP_NET_META_VLAN_TCI_MASK,
vlan_info);
}
data += 4;
break;
case NFP_NET_META_PORTID:
meta->portid = get_unaligned_be32(data);
data += 4;
Expand Down Expand Up @@ -1169,9 +1180,11 @@ static int nfp_nfdk_rx(struct nfp_net_rx_ring *rx_ring, int budget)

nfp_nfdk_rx_csum(dp, r_vec, rxd, &meta, skb);

if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
le16_to_cpu(rxd->rxd.vlan));
if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) {
nfp_nfdk_rx_drop(dp, r_vec, rx_ring, NULL, skb);
continue;
}

if (meta_len_xdp)
skb_metadata_set(skb, meta_len_xdp);

Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/netronome/nfp/nfdk/rings.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ nfp_nfdk_print_tx_descs(struct seq_file *file,
NFP_NET_CFG_CTRL_L2BC | NFP_NET_CFG_CTRL_L2MC | \
NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM | \
NFP_NET_CFG_CTRL_RXVLAN | \
NFP_NET_CFG_CTRL_RXVLAN_V2 | NFP_NET_CFG_CTRL_RXQINQ | \
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 | \
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/ethernet/netronome/nfp/nfp_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ struct nfp_net_rx_desc {
};

#define NFP_NET_META_FIELD_MASK GENMASK(NFP_NET_META_FIELD_SIZE - 1, 0)
#define NFP_NET_VLAN_CTAG 0
#define NFP_NET_VLAN_STAG 1

struct nfp_meta_parsed {
u8 hash_type;
Expand All @@ -256,6 +258,11 @@ struct nfp_meta_parsed {
u32 mark;
u32 portid;
__wsum csum;
struct {
bool stripped;
u8 tpid;
u16 tci;
} vlan;
};

struct nfp_net_rx_hash {
Expand Down
68 changes: 56 additions & 12 deletions drivers/net/ethernet/netronome/nfp/nfp_net_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1695,16 +1695,18 @@ static int nfp_net_set_features(struct net_device *netdev,

if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
if (features & NETIF_F_HW_VLAN_CTAG_RX)
new_ctrl |= NFP_NET_CFG_CTRL_RXVLAN;
new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXVLAN_V2 ?:
NFP_NET_CFG_CTRL_RXVLAN;
else
new_ctrl &= ~NFP_NET_CFG_CTRL_RXVLAN;
new_ctrl &= ~NFP_NET_CFG_CTRL_RXVLAN_ANY;
}

if (changed & NETIF_F_HW_VLAN_CTAG_TX) {
if (features & NETIF_F_HW_VLAN_CTAG_TX)
new_ctrl |= NFP_NET_CFG_CTRL_TXVLAN;
new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_TXVLAN_V2 ?:
NFP_NET_CFG_CTRL_TXVLAN;
else
new_ctrl &= ~NFP_NET_CFG_CTRL_TXVLAN;
new_ctrl &= ~NFP_NET_CFG_CTRL_TXVLAN_ANY;
}

if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
Expand All @@ -1714,6 +1716,13 @@ static int nfp_net_set_features(struct net_device *netdev,
new_ctrl &= ~NFP_NET_CFG_CTRL_CTAG_FILTER;
}

if (changed & NETIF_F_HW_VLAN_STAG_RX) {
if (features & NETIF_F_HW_VLAN_STAG_RX)
new_ctrl |= NFP_NET_CFG_CTRL_RXQINQ;
else
new_ctrl &= ~NFP_NET_CFG_CTRL_RXQINQ;
}

if (changed & NETIF_F_SG) {
if (features & NETIF_F_SG)
new_ctrl |= NFP_NET_CFG_CTRL_GATHER;
Expand Down Expand Up @@ -1742,6 +1751,27 @@ static int nfp_net_set_features(struct net_device *netdev,
return 0;
}

static netdev_features_t
nfp_net_fix_features(struct net_device *netdev,
netdev_features_t features)
{
if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
(features & NETIF_F_HW_VLAN_STAG_RX)) {
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
features &= ~NETIF_F_HW_VLAN_CTAG_RX;
netdev->wanted_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
netdev_warn(netdev,
"S-tag and C-tag stripping can't be enabled at the same time. Enabling S-tag stripping and disabling C-tag stripping\n");
} else if (netdev->features & NETIF_F_HW_VLAN_STAG_RX) {
features &= ~NETIF_F_HW_VLAN_STAG_RX;
netdev->wanted_features &= ~NETIF_F_HW_VLAN_STAG_RX;
netdev_warn(netdev,
"S-tag and C-tag stripping can't be enabled at the same time. Enabling C-tag stripping and disabling S-tag stripping\n");
}
}
return features;
}

static netdev_features_t
nfp_net_features_check(struct sk_buff *skb, struct net_device *dev,
netdev_features_t features)
Expand Down Expand Up @@ -1977,6 +2007,7 @@ const struct net_device_ops nfp_nfd3_netdev_ops = {
.ndo_change_mtu = nfp_net_change_mtu,
.ndo_set_mac_address = nfp_net_set_mac_address,
.ndo_set_features = nfp_net_set_features,
.ndo_fix_features = nfp_net_fix_features,
.ndo_features_check = nfp_net_features_check,
.ndo_get_phys_port_name = nfp_net_get_phys_port_name,
.ndo_bpf = nfp_net_xdp,
Expand Down Expand Up @@ -2008,6 +2039,7 @@ const struct net_device_ops nfp_nfdk_netdev_ops = {
.ndo_change_mtu = nfp_net_change_mtu,
.ndo_set_mac_address = nfp_net_set_mac_address,
.ndo_set_features = nfp_net_set_features,
.ndo_fix_features = nfp_net_fix_features,
.ndo_features_check = nfp_net_features_check,
.ndo_get_phys_port_name = nfp_net_get_phys_port_name,
.ndo_bpf = nfp_net_xdp,
Expand Down Expand Up @@ -2061,7 +2093,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%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%s%s%s\n",
nn->cap,
nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "",
nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "",
Expand All @@ -2070,6 +2102,9 @@ void nfp_net_info(struct nfp_net *nn)
nn->cap & NFP_NET_CFG_CTRL_TXCSUM ? "TXCSUM " : "",
nn->cap & NFP_NET_CFG_CTRL_RXVLAN ? "RXVLAN " : "",
nn->cap & NFP_NET_CFG_CTRL_TXVLAN ? "TXVLAN " : "",
nn->cap & NFP_NET_CFG_CTRL_RXQINQ ? "RXQINQ " : "",
nn->cap & NFP_NET_CFG_CTRL_RXVLAN_V2 ? "RXVLANv2 " : "",
nn->cap & NFP_NET_CFG_CTRL_TXVLAN_V2 ? "TXVLAN2 " : "",
nn->cap & NFP_NET_CFG_CTRL_SCATTER ? "SCATTER " : "",
nn->cap & NFP_NET_CFG_CTRL_GATHER ? "GATHER " : "",
nn->cap & NFP_NET_CFG_CTRL_LSO ? "TSO1 " : "",
Expand Down Expand Up @@ -2357,31 +2392,40 @@ static void nfp_net_netdev_init(struct nfp_net *nn)

netdev->vlan_features = netdev->hw_features;

if (nn->cap & NFP_NET_CFG_CTRL_RXVLAN) {
if (nn->cap & NFP_NET_CFG_CTRL_RXVLAN_ANY) {
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXVLAN;
nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXVLAN_V2 ?:
NFP_NET_CFG_CTRL_RXVLAN;
}
if (nn->cap & NFP_NET_CFG_CTRL_TXVLAN) {
if (nn->cap & NFP_NET_CFG_CTRL_TXVLAN_ANY) {
if (nn->cap & NFP_NET_CFG_CTRL_LSO2) {
nn_warn(nn, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n");
} else {
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
nn->dp.ctrl |= NFP_NET_CFG_CTRL_TXVLAN;
nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_TXVLAN_V2 ?:
NFP_NET_CFG_CTRL_TXVLAN;
}
}
if (nn->cap & NFP_NET_CFG_CTRL_CTAG_FILTER) {
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
nn->dp.ctrl |= NFP_NET_CFG_CTRL_CTAG_FILTER;
}
if (nn->cap & NFP_NET_CFG_CTRL_RXQINQ) {
netdev->hw_features |= NETIF_F_HW_VLAN_STAG_RX;
nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXQINQ;
}

netdev->features = netdev->hw_features;

if (nfp_app_has_tc(nn->app) && nn->port)
netdev->hw_features |= NETIF_F_HW_TC;

/* Advertise but disable TSO by default. */
netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY;
/* Advertise but disable TSO by default.
* C-Tag strip and S-Tag strip can't be supported simultaneously,
* so enable C-Tag strip and disable S-Tag strip by default.
*/
netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_STAG_RX);
nn->dp.ctrl &= ~(NFP_NET_CFG_CTRL_LSO_ANY | NFP_NET_CFG_CTRL_RXQINQ);

/* Finalise the netdev setup */
switch (nn->dp.ops->version) {
Expand Down
Loading

0 comments on commit fd4b96c

Please sign in to comment.