Commit fd4b96c4 authored by David S. Miller's avatar David S. Miller

Merge branch 'nfp-vlan-strip-and-insert'

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 5ee4bba2 d80702ff
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/bpf_trace.h> #include <linux/bpf_trace.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/bitfield.h>
#include "../nfp_app.h" #include "../nfp_app.h"
#include "../nfp_net.h" #include "../nfp_net.h"
...@@ -166,30 +167,35 @@ nfp_nfd3_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec, ...@@ -166,30 +167,35 @@ nfp_nfd3_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
u64_stats_update_end(&r_vec->tx_sync); 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); struct metadata_dst *md_dst = skb_metadata_dst(skb);
unsigned char *data; unsigned char *data;
bool vlan_insert;
u32 meta_id = 0; u32 meta_id = 0;
int md_bytes; int md_bytes;
if (likely(!md_dst && !tls_handle)) if (unlikely(md_dst || tls_handle)) {
return 0; if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX))
if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX)) { md_dst = NULL;
if (!tls_handle)
return 0;
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))) if (unlikely(skb_cow_head(skb, md_bytes)))
return -ENOMEM; return -ENOMEM;
meta_id = 0;
data = skb_push(skb, md_bytes) + md_bytes; data = skb_push(skb, md_bytes) + md_bytes;
if (md_dst) { if (md_dst) {
data -= 4; data -= NFP_NET_META_PORTID_SIZE;
put_unaligned_be32(md_dst->u.port_info.port_id, data); put_unaligned_be32(md_dst->u.port_info.port_id, data);
meta_id = NFP_NET_META_PORTID; meta_id = NFP_NET_META_PORTID;
} }
...@@ -197,13 +203,23 @@ static int nfp_nfd3_prep_tx_meta(struct sk_buff *skb, u64 tls_handle) ...@@ -197,13 +203,23 @@ static int nfp_nfd3_prep_tx_meta(struct sk_buff *skb, u64 tls_handle)
/* conn handle is opaque, we just use u64 to be able to quickly /* conn handle is opaque, we just use u64 to be able to quickly
* compare it to zero * compare it to zero
*/ */
data -= 8; data -= NFP_NET_META_CONN_HANDLE_SIZE;
memcpy(data, &tls_handle, sizeof(tls_handle)); memcpy(data, &tls_handle, sizeof(tls_handle));
meta_id <<= NFP_NET_META_FIELD_SIZE; meta_id <<= NFP_NET_META_FIELD_SIZE;
meta_id |= NFP_NET_META_CONN_HANDLE; 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); put_unaligned_be32(meta_id, data);
return md_bytes; return md_bytes;
...@@ -257,7 +273,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev) ...@@ -257,7 +273,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK; 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)) if (unlikely(md_bytes < 0))
goto err_flush; goto err_flush;
...@@ -703,7 +719,7 @@ bool ...@@ -703,7 +719,7 @@ bool
nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
void *data, void *pkt, unsigned int pkt_len, int meta_len) 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); meta_info = get_unaligned_be32(data);
data += 4; data += 4;
...@@ -721,6 +737,17 @@ nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, ...@@ -721,6 +737,17 @@ nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
meta->mark = get_unaligned_be32(data); meta->mark = get_unaligned_be32(data);
data += 4; data += 4;
break; 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: case NFP_NET_META_PORTID:
meta->portid = get_unaligned_be32(data); meta->portid = get_unaligned_be32(data);
data += 4; data += 4;
...@@ -1049,9 +1076,11 @@ static int nfp_nfd3_rx(struct nfp_net_rx_ring *rx_ring, int budget) ...@@ -1049,9 +1076,11 @@ static int nfp_nfd3_rx(struct nfp_net_rx_ring *rx_ring, int budget)
} }
#endif #endif
if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) {
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), nfp_nfd3_rx_drop(dp, r_vec, rx_ring, NULL, skb);
le16_to_cpu(rxd->rxd.vlan)); continue;
}
if (meta_len_xdp) if (meta_len_xdp)
skb_metadata_set(skb, meta_len_xdp); skb_metadata_set(skb, meta_len_xdp);
......
...@@ -247,6 +247,8 @@ nfp_nfd3_print_tx_descs(struct seq_file *file, ...@@ -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_L2BC | NFP_NET_CFG_CTRL_L2MC | \
NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM | \ 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 | 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_GATHER | NFP_NET_CFG_CTRL_LSO | \
NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA | \ 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_RINGCFG | NFP_NET_CFG_CTRL_RSS | \
......
...@@ -94,9 +94,12 @@ static void nfp_nfd3_xsk_rx_skb(struct nfp_net_rx_ring *rx_ring, ...@@ -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); nfp_nfd3_rx_csum(dp, r_vec, rxd, meta, skb);
if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) if (unlikely(!nfp_net_vlan_strip(skb, rxd, meta))) {
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), dev_kfree_skb_any(skb);
le16_to_cpu(rxd->rxd.vlan)); nfp_net_xsk_rx_drop(r_vec, xrxbuf);
return;
}
if (meta_xdp) if (meta_xdp)
skb_metadata_set(skb, skb_metadata_set(skb,
xrxbuf->xdp->data - xrxbuf->xdp->data_meta); xrxbuf->xdp->data - xrxbuf->xdp->data_meta);
......
...@@ -716,7 +716,7 @@ static bool ...@@ -716,7 +716,7 @@ static bool
nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
void *data, void *pkt, unsigned int pkt_len, int meta_len) 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); meta_info = get_unaligned_be32(data);
data += 4; data += 4;
...@@ -734,6 +734,17 @@ nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, ...@@ -734,6 +734,17 @@ nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
meta->mark = get_unaligned_be32(data); meta->mark = get_unaligned_be32(data);
data += 4; data += 4;
break; 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: case NFP_NET_META_PORTID:
meta->portid = get_unaligned_be32(data); meta->portid = get_unaligned_be32(data);
data += 4; data += 4;
...@@ -1169,9 +1180,11 @@ static int nfp_nfdk_rx(struct nfp_net_rx_ring *rx_ring, int budget) ...@@ -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); nfp_nfdk_rx_csum(dp, r_vec, rxd, &meta, skb);
if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) {
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), nfp_nfdk_rx_drop(dp, r_vec, rx_ring, NULL, skb);
le16_to_cpu(rxd->rxd.vlan)); continue;
}
if (meta_len_xdp) if (meta_len_xdp)
skb_metadata_set(skb, meta_len_xdp); skb_metadata_set(skb, meta_len_xdp);
......
...@@ -168,6 +168,7 @@ nfp_nfdk_print_tx_descs(struct seq_file *file, ...@@ -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_L2BC | NFP_NET_CFG_CTRL_L2MC | \
NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM | \ NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM | \
NFP_NET_CFG_CTRL_RXVLAN | \ 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_GATHER | NFP_NET_CFG_CTRL_LSO | \
NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA | \ 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_RINGCFG | NFP_NET_CFG_CTRL_IRQMOD | \
......
...@@ -248,6 +248,8 @@ struct nfp_net_rx_desc { ...@@ -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_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 { struct nfp_meta_parsed {
u8 hash_type; u8 hash_type;
...@@ -256,6 +258,11 @@ struct nfp_meta_parsed { ...@@ -256,6 +258,11 @@ struct nfp_meta_parsed {
u32 mark; u32 mark;
u32 portid; u32 portid;
__wsum csum; __wsum csum;
struct {
bool stripped;
u8 tpid;
u16 tci;
} vlan;
}; };
struct nfp_net_rx_hash { struct nfp_net_rx_hash {
......
...@@ -1695,16 +1695,18 @@ static int nfp_net_set_features(struct net_device *netdev, ...@@ -1695,16 +1695,18 @@ static int nfp_net_set_features(struct net_device *netdev,
if (changed & NETIF_F_HW_VLAN_CTAG_RX) { if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
if (features & 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 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 (changed & NETIF_F_HW_VLAN_CTAG_TX) {
if (features & 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 else
new_ctrl &= ~NFP_NET_CFG_CTRL_TXVLAN; new_ctrl &= ~NFP_NET_CFG_CTRL_TXVLAN_ANY;
} }
if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
...@@ -1714,6 +1716,13 @@ static int nfp_net_set_features(struct net_device *netdev, ...@@ -1714,6 +1716,13 @@ static int nfp_net_set_features(struct net_device *netdev,
new_ctrl &= ~NFP_NET_CFG_CTRL_CTAG_FILTER; 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 (changed & NETIF_F_SG) {
if (features & NETIF_F_SG) if (features & NETIF_F_SG)
new_ctrl |= NFP_NET_CFG_CTRL_GATHER; new_ctrl |= NFP_NET_CFG_CTRL_GATHER;
...@@ -1742,6 +1751,27 @@ static int nfp_net_set_features(struct net_device *netdev, ...@@ -1742,6 +1751,27 @@ static int nfp_net_set_features(struct net_device *netdev,
return 0; 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 static netdev_features_t
nfp_net_features_check(struct sk_buff *skb, struct net_device *dev, nfp_net_features_check(struct sk_buff *skb, struct net_device *dev,
netdev_features_t features) netdev_features_t features)
...@@ -1977,6 +2007,7 @@ const struct net_device_ops nfp_nfd3_netdev_ops = { ...@@ -1977,6 +2007,7 @@ const struct net_device_ops nfp_nfd3_netdev_ops = {
.ndo_change_mtu = nfp_net_change_mtu, .ndo_change_mtu = nfp_net_change_mtu,
.ndo_set_mac_address = nfp_net_set_mac_address, .ndo_set_mac_address = nfp_net_set_mac_address,
.ndo_set_features = nfp_net_set_features, .ndo_set_features = nfp_net_set_features,
.ndo_fix_features = nfp_net_fix_features,
.ndo_features_check = nfp_net_features_check, .ndo_features_check = nfp_net_features_check,
.ndo_get_phys_port_name = nfp_net_get_phys_port_name, .ndo_get_phys_port_name = nfp_net_get_phys_port_name,
.ndo_bpf = nfp_net_xdp, .ndo_bpf = nfp_net_xdp,
...@@ -2008,6 +2039,7 @@ const struct net_device_ops nfp_nfdk_netdev_ops = { ...@@ -2008,6 +2039,7 @@ const struct net_device_ops nfp_nfdk_netdev_ops = {
.ndo_change_mtu = nfp_net_change_mtu, .ndo_change_mtu = nfp_net_change_mtu,
.ndo_set_mac_address = nfp_net_set_mac_address, .ndo_set_mac_address = nfp_net_set_mac_address,
.ndo_set_features = nfp_net_set_features, .ndo_set_features = nfp_net_set_features,
.ndo_fix_features = nfp_net_fix_features,
.ndo_features_check = nfp_net_features_check, .ndo_features_check = nfp_net_features_check,
.ndo_get_phys_port_name = nfp_net_get_phys_port_name, .ndo_get_phys_port_name = nfp_net_get_phys_port_name,
.ndo_bpf = nfp_net_xdp, .ndo_bpf = nfp_net_xdp,
...@@ -2061,7 +2093,7 @@ void nfp_net_info(struct nfp_net *nn) ...@@ -2061,7 +2093,7 @@ void nfp_net_info(struct nfp_net *nn)
nn->fw_ver.extend, nn->fw_ver.class, nn->fw_ver.extend, nn->fw_ver.class,
nn->fw_ver.major, nn->fw_ver.minor, nn->fw_ver.major, nn->fw_ver.minor,
nn->max_mtu); 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,
nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "", nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "",
nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "", nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "",
...@@ -2070,6 +2102,9 @@ void nfp_net_info(struct nfp_net *nn) ...@@ -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_TXCSUM ? "TXCSUM " : "",
nn->cap & NFP_NET_CFG_CTRL_RXVLAN ? "RXVLAN " : "", nn->cap & NFP_NET_CFG_CTRL_RXVLAN ? "RXVLAN " : "",
nn->cap & NFP_NET_CFG_CTRL_TXVLAN ? "TXVLAN " : "", 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_SCATTER ? "SCATTER " : "",
nn->cap & NFP_NET_CFG_CTRL_GATHER ? "GATHER " : "", nn->cap & NFP_NET_CFG_CTRL_GATHER ? "GATHER " : "",
nn->cap & NFP_NET_CFG_CTRL_LSO ? "TSO1 " : "", nn->cap & NFP_NET_CFG_CTRL_LSO ? "TSO1 " : "",
...@@ -2357,31 +2392,40 @@ static void nfp_net_netdev_init(struct nfp_net *nn) ...@@ -2357,31 +2392,40 @@ static void nfp_net_netdev_init(struct nfp_net *nn)
netdev->vlan_features = netdev->hw_features; 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; 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) { if (nn->cap & NFP_NET_CFG_CTRL_LSO2) {
nn_warn(nn, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n"); nn_warn(nn, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n");
} else { } else {
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX; 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) { if (nn->cap & NFP_NET_CFG_CTRL_CTAG_FILTER) {
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
nn->dp.ctrl |= NFP_NET_CFG_CTRL_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; netdev->features = netdev->hw_features;
if (nfp_app_has_tc(nn->app) && nn->port) if (nfp_app_has_tc(nn->app) && nn->port)
netdev->hw_features |= NETIF_F_HW_TC; netdev->hw_features |= NETIF_F_HW_TC;
/* Advertise but disable TSO by default. */ /* Advertise but disable TSO by default.
netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); * C-Tag strip and S-Tag strip can't be supported simultaneously,
nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY; * 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 */ /* Finalise the netdev setup */
switch (nn->dp.ops->version) { switch (nn->dp.ops->version) {
......
...@@ -31,10 +31,16 @@ ...@@ -31,10 +31,16 @@
#define NFP_NET_LSO_MAX_HDR_SZ 255 #define NFP_NET_LSO_MAX_HDR_SZ 255
#define NFP_NET_LSO_MAX_SEGS 64 #define NFP_NET_LSO_MAX_SEGS 64
/* working with metadata vlan api (NFD version >= 2.0) */
#define NFP_NET_META_VLAN_STRIP BIT(31)
#define NFP_NET_META_VLAN_TPID_MASK GENMASK(19, 16)
#define NFP_NET_META_VLAN_TCI_MASK GENMASK(15, 0)
/* Prepend field types */ /* Prepend field types */
#define NFP_NET_META_FIELD_SIZE 4 #define NFP_NET_META_FIELD_SIZE 4
#define NFP_NET_META_HASH 1 /* next field carries hash type */ #define NFP_NET_META_HASH 1 /* next field carries hash type */
#define NFP_NET_META_MARK 2 #define NFP_NET_META_MARK 2
#define NFP_NET_META_VLAN 4 /* ctag or stag type */
#define NFP_NET_META_PORTID 5 #define NFP_NET_META_PORTID 5
#define NFP_NET_META_CSUM 6 /* checksum complete type */ #define NFP_NET_META_CSUM 6 /* checksum complete type */
#define NFP_NET_META_CONN_HANDLE 7 #define NFP_NET_META_CONN_HANDLE 7
...@@ -42,6 +48,10 @@ ...@@ -42,6 +48,10 @@
#define NFP_META_PORT_ID_CTRL ~0U #define NFP_META_PORT_ID_CTRL ~0U
/* Prepend field sizes */
#define NFP_NET_META_VLAN_SIZE 4
#define NFP_NET_META_PORTID_SIZE 4
#define NFP_NET_META_CONN_HANDLE_SIZE 8
/* Hash type pre-pended when a RSS hash was computed */ /* Hash type pre-pended when a RSS hash was computed */
#define NFP_NET_RSS_NONE 0 #define NFP_NET_RSS_NONE 0
#define NFP_NET_RSS_IPV4 1 #define NFP_NET_RSS_IPV4 1
...@@ -89,12 +99,15 @@ ...@@ -89,12 +99,15 @@
#define NFP_NET_CFG_CTRL_LSO (0x1 << 10) /* LSO/TSO (version 1) */ #define NFP_NET_CFG_CTRL_LSO (0x1 << 10) /* LSO/TSO (version 1) */
#define NFP_NET_CFG_CTRL_CTAG_FILTER (0x1 << 11) /* VLAN CTAG filtering */ #define NFP_NET_CFG_CTRL_CTAG_FILTER (0x1 << 11) /* VLAN CTAG filtering */
#define NFP_NET_CFG_CTRL_CMSG_DATA (0x1 << 12) /* RX cmsgs on data Qs */ #define NFP_NET_CFG_CTRL_CMSG_DATA (0x1 << 12) /* RX cmsgs on data Qs */
#define NFP_NET_CFG_CTRL_RXQINQ (0x1 << 13) /* Enable S-tag strip */
#define NFP_NET_CFG_CTRL_RXVLAN_V2 (0x1 << 15) /* Enable C-tag strip */
#define NFP_NET_CFG_CTRL_RINGCFG (0x1 << 16) /* Ring runtime changes */ #define NFP_NET_CFG_CTRL_RINGCFG (0x1 << 16) /* Ring runtime changes */
#define NFP_NET_CFG_CTRL_RSS (0x1 << 17) /* RSS (version 1) */ #define NFP_NET_CFG_CTRL_RSS (0x1 << 17) /* RSS (version 1) */
#define NFP_NET_CFG_CTRL_IRQMOD (0x1 << 18) /* Interrupt moderation */ #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_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_TXRWB (0x1 << 21) /* Write-back of TX ring*/
#define NFP_NET_CFG_CTRL_VEPA (0x1 << 22) /* Enable VEPA mode */ #define NFP_NET_CFG_CTRL_VEPA (0x1 << 22) /* Enable VEPA mode */
#define NFP_NET_CFG_CTRL_TXVLAN_V2 (0x1 << 23) /* Enable VLAN C-tag insert*/
#define NFP_NET_CFG_CTRL_VXLAN (0x1 << 24) /* VXLAN tunnel support */ #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_NVGRE (0x1 << 25) /* NVGRE tunnel support */
#define NFP_NET_CFG_CTRL_BPF (0x1 << 27) /* BPF offload capable */ #define NFP_NET_CFG_CTRL_BPF (0x1 << 27) /* BPF offload capable */
...@@ -111,6 +124,10 @@ ...@@ -111,6 +124,10 @@
NFP_NET_CFG_CTRL_CSUM_COMPLETE) NFP_NET_CFG_CTRL_CSUM_COMPLETE)
#define NFP_NET_CFG_CTRL_CHAIN_META (NFP_NET_CFG_CTRL_RSS2 | \ #define NFP_NET_CFG_CTRL_CHAIN_META (NFP_NET_CFG_CTRL_RSS2 | \
NFP_NET_CFG_CTRL_CSUM_COMPLETE) NFP_NET_CFG_CTRL_CSUM_COMPLETE)
#define NFP_NET_CFG_CTRL_RXVLAN_ANY (NFP_NET_CFG_CTRL_RXVLAN | \
NFP_NET_CFG_CTRL_RXVLAN_V2)
#define NFP_NET_CFG_CTRL_TXVLAN_ANY (NFP_NET_CFG_CTRL_TXVLAN | \
NFP_NET_CFG_CTRL_TXVLAN_V2)
#define NFP_NET_CFG_UPDATE 0x0004 #define NFP_NET_CFG_UPDATE 0x0004
#define NFP_NET_CFG_UPDATE_GEN (0x1 << 0) /* General update */ #define NFP_NET_CFG_UPDATE_GEN (0x1 << 0) /* General update */
......
...@@ -440,3 +440,27 @@ bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb) ...@@ -440,3 +440,27 @@ bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb)
return ret; return ret;
} }
bool nfp_net_vlan_strip(struct sk_buff *skb, const struct nfp_net_rx_desc *rxd,
const struct nfp_meta_parsed *meta)
{
u16 tpid = 0, tci = 0;
if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) {
tpid = ETH_P_8021Q;
tci = le16_to_cpu(rxd->rxd.vlan);
} else if (meta->vlan.stripped) {
if (meta->vlan.tpid == NFP_NET_VLAN_CTAG)
tpid = ETH_P_8021Q;
else if (meta->vlan.tpid == NFP_NET_VLAN_STAG)
tpid = ETH_P_8021AD;
else
return false;
tci = meta->vlan.tci;
}
if (tpid)
__vlan_hwaccel_put_tag(skb, htons(tpid), tci);
return true;
}
...@@ -106,6 +106,8 @@ int nfp_net_tx_rings_prepare(struct nfp_net *nn, struct nfp_net_dp *dp); ...@@ -106,6 +106,8 @@ int nfp_net_tx_rings_prepare(struct nfp_net *nn, struct nfp_net_dp *dp);
void nfp_net_rx_rings_free(struct nfp_net_dp *dp); void nfp_net_rx_rings_free(struct nfp_net_dp *dp);
void nfp_net_tx_rings_free(struct nfp_net_dp *dp); void nfp_net_tx_rings_free(struct nfp_net_dp *dp);
void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring); void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring);
bool nfp_net_vlan_strip(struct sk_buff *skb, const struct nfp_net_rx_desc *rxd,
const struct nfp_meta_parsed *meta);
enum nfp_nfd_version { enum nfp_nfd_version {
NFP_NFD_VER_NFD3, NFP_NFD_VER_NFD3,
......
...@@ -365,9 +365,9 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, ...@@ -365,9 +365,9 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
netdev->vlan_features = netdev->hw_features; netdev->vlan_features = netdev->hw_features;
if (repr_cap & NFP_NET_CFG_CTRL_RXVLAN) if (repr_cap & NFP_NET_CFG_CTRL_RXVLAN_ANY)
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
if (repr_cap & NFP_NET_CFG_CTRL_TXVLAN) { if (repr_cap & NFP_NET_CFG_CTRL_TXVLAN_ANY) {
if (repr_cap & NFP_NET_CFG_CTRL_LSO2) if (repr_cap & NFP_NET_CFG_CTRL_LSO2)
netdev_warn(netdev, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n"); netdev_warn(netdev, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n");
else else
...@@ -375,11 +375,16 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, ...@@ -375,11 +375,16 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
} }
if (repr_cap & NFP_NET_CFG_CTRL_CTAG_FILTER) if (repr_cap & NFP_NET_CFG_CTRL_CTAG_FILTER)
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
if (repr_cap & NFP_NET_CFG_CTRL_RXQINQ)
netdev->hw_features |= NETIF_F_HW_VLAN_STAG_RX;
netdev->features = netdev->hw_features; netdev->features = netdev->hw_features;
/* Advertise but disable TSO by default. */ /* Advertise but disable TSO by default.
netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); * 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);
netif_set_tso_max_segs(netdev, NFP_NET_LSO_MAX_SEGS); netif_set_tso_max_segs(netdev, NFP_NET_LSO_MAX_SEGS);
netdev->priv_flags |= IFF_NO_QUEUE | IFF_DISABLE_NETPOLL; netdev->priv_flags |= IFF_NO_QUEUE | IFF_DISABLE_NETPOLL;
......
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