nfp: support LSO2 capability
authorEdwin Peer <edwin.peer@netronome.com>
Tue, 16 May 2017 00:55:17 +0000 (17:55 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 May 2017 16:59:02 +0000 (12:59 -0400)
Firmware advertising the LSO2 capability exploits driver provided L3 and L4
offsets in order to avoid parsing packet headers in the TX path. The vlan
field in struct nfp_net_tx_desc is repurposed, making TXVLAN a mutually
exclusive configuration to LSO2.

Signed-off-by: Edwin Peer <edwin.peer@netronome.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/nfp_net.h
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h

index 6bad11e5b8456a280030a32c958e980b6ec9b828..c6b7141dc50d163a3714106f3bd521dbabcb4098 100644 (file)
@@ -155,8 +155,13 @@ struct nfp_net_tx_desc {
                        __le16 mss;     /* MSS to be used for LSO */
                        u8 lso_hdrlen;  /* LSO, TCP payload offset */
                        u8 flags;       /* TX Flags, see @PCIE_DESC_TX_* */
-
-                       __le16 vlan;    /* VLAN tag to add if indicated */
+                       union {
+                               struct {
+                                       u8 l3_offset; /* L3 header offset */
+                                       u8 l4_offset; /* L4 header offset */
+                               };
+                               __le16 vlan; /* VLAN tag to add if indicated */
+                       };
                        __le16 data_len; /* Length of frame + meta data */
                } __packed;
                __le32 vals[4];
index 0cebe9098451ea1a822a3a9039584e9843ef7e9c..5e8049a84d162805b9803f596d361b0c356a7ccc 100644 (file)
@@ -667,11 +667,16 @@ static void nfp_net_tx_tso(struct nfp_net_r_vector *r_vec,
        if (!skb_is_gso(skb))
                return;
 
-       if (!skb->encapsulation)
+       if (!skb->encapsulation) {
+               txd->l3_offset = skb_network_offset(skb);
+               txd->l4_offset = skb_transport_offset(skb);
                hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
-       else
+       } else {
+               txd->l3_offset = skb_inner_network_offset(skb);
+               txd->l4_offset = skb_inner_transport_offset(skb);
                hdrlen = skb_inner_transport_header(skb) - skb->data +
                        inner_tcp_hdrlen(skb);
+       }
 
        txbuf->pkt_cnt = skb_shinfo(skb)->gso_segs;
        txbuf->real_len += hdrlen * (txbuf->pkt_cnt - 1);
@@ -825,10 +830,9 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
        txd->mss = 0;
        txd->lso_hdrlen = 0;
 
+       /* Do not reorder - tso may adjust pkt cnt, vlan may override fields */
        nfp_net_tx_tso(r_vec, txbuf, txd, skb);
-
        nfp_net_tx_csum(dp, r_vec, txbuf, txd, skb);
-
        if (skb_vlan_tag_present(skb) && dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN) {
                txd->flags |= PCIE_DESC_TX_VLAN;
                txd->vlan = cpu_to_le16(skb_vlan_tag_get(skb));
@@ -2724,9 +2728,10 @@ static int nfp_net_set_features(struct net_device *netdev,
 
        if (changed & (NETIF_F_TSO | NETIF_F_TSO6)) {
                if (features & (NETIF_F_TSO | NETIF_F_TSO6))
-                       new_ctrl |= NFP_NET_CFG_CTRL_LSO;
+                       new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_LSO2 ?:
+                                             NFP_NET_CFG_CTRL_LSO;
                else
-                       new_ctrl &= ~NFP_NET_CFG_CTRL_LSO;
+                       new_ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY;
        }
 
        if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
@@ -3032,7 +3037,7 @@ void nfp_net_info(struct nfp_net *nn)
                nn->fw_ver.resv, 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\n",
+       nn_info(nn, "CAP: %#x %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 " : "",
@@ -3043,7 +3048,8 @@ void nfp_net_info(struct nfp_net *nn)
                nn->cap & NFP_NET_CFG_CTRL_TXVLAN   ? "TXVLAN "   : "",
                nn->cap & NFP_NET_CFG_CTRL_SCATTER  ? "SCATTER "  : "",
                nn->cap & NFP_NET_CFG_CTRL_GATHER   ? "GATHER "   : "",
-               nn->cap & NFP_NET_CFG_CTRL_LSO      ? "TSO "      : "",
+               nn->cap & NFP_NET_CFG_CTRL_LSO      ? "TSO1 "     : "",
+               nn->cap & NFP_NET_CFG_CTRL_LSO2     ? "TSO2 "     : "",
                nn->cap & NFP_NET_CFG_CTRL_RSS      ? "RSS "      : "",
                nn->cap & NFP_NET_CFG_CTRL_L2SWITCH ? "L2SWITCH " : "",
                nn->cap & NFP_NET_CFG_CTRL_MSIXAUTO ? "AUTOMASK " : "",
@@ -3249,9 +3255,11 @@ int nfp_net_netdev_init(struct net_device *netdev)
                netdev->hw_features |= NETIF_F_SG;
                nn->dp.ctrl |= NFP_NET_CFG_CTRL_GATHER;
        }
-       if ((nn->cap & NFP_NET_CFG_CTRL_LSO) && nn->fw_ver.major > 2) {
+       if ((nn->cap & NFP_NET_CFG_CTRL_LSO && nn->fw_ver.major > 2) ||
+           nn->cap & NFP_NET_CFG_CTRL_LSO2) {
                netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
-               nn->dp.ctrl |= NFP_NET_CFG_CTRL_LSO;
+               nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_LSO2 ?:
+                                        NFP_NET_CFG_CTRL_LSO;
        }
        if (nn->cap & NFP_NET_CFG_CTRL_RSS) {
                netdev->hw_features |= NETIF_F_RXHASH;
@@ -3275,8 +3283,12 @@ int nfp_net_netdev_init(struct net_device *netdev)
                nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXVLAN;
        }
        if (nn->cap & NFP_NET_CFG_CTRL_TXVLAN) {
-               netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
-               nn->dp.ctrl |= NFP_NET_CFG_CTRL_TXVLAN;
+               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;
+               }
        }
 
        netdev->features = netdev->hw_features;
@@ -3286,7 +3298,7 @@ int nfp_net_netdev_init(struct net_device *netdev)
 
        /* Advertise but disable TSO by default. */
        netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-       nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO;
+       nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY;
 
        /* Allow L2 Broadcast and Multicast through by default, if supported */
        if (nn->cap & NFP_NET_CFG_CTRL_L2BC)
index d04ccc9f61162c73bbe67f68cf5dfaed5ecb4a69..1575e8fdb541660d41e469198f1d5b7b6da40c5d 100644 (file)
 #define   NFP_NET_CFG_CTRL_TXVLAN         (0x1 <<  7) /* Enable VLAN insert */
 #define   NFP_NET_CFG_CTRL_SCATTER        (0x1 <<  8) /* Scatter DMA */
 #define   NFP_NET_CFG_CTRL_GATHER         (0x1 <<  9) /* Gather DMA */
-#define   NFP_NET_CFG_CTRL_LSO            (0x1 << 10) /* LSO/TSO */
+#define   NFP_NET_CFG_CTRL_LSO            (0x1 << 10) /* LSO/TSO (version 1) */
 #define   NFP_NET_CFG_CTRL_RINGCFG        (0x1 << 16) /* Ring runtime changes */
 #define   NFP_NET_CFG_CTRL_RSS            (0x1 << 17) /* RSS */
 #define   NFP_NET_CFG_CTRL_IRQMOD         (0x1 << 18) /* Interrupt moderation */
 #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 */
+#define   NFP_NET_CFG_CTRL_LSO2                  (0x1 << 28) /* LSO/TSO (version 2) */
+
+#define NFP_NET_CFG_CTRL_LSO_ANY       (NFP_NET_CFG_CTRL_LSO | \
+                                        NFP_NET_CFG_CTRL_LSO2)
+
 #define NFP_NET_CFG_UPDATE              0x0004
 #define   NFP_NET_CFG_UPDATE_GEN          (0x1 <<  0) /* General update */
 #define   NFP_NET_CFG_UPDATE_RING         (0x1 <<  1) /* Ring config change */