Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / ethernet / netronome / nfp / nfp_net_common.c
index 39dadfc..aee3fd2 100644 (file)
@@ -60,6 +60,7 @@
 
 #include <linux/ktime.h>
 
+#include <net/pkt_cls.h>
 #include <net/vxlan.h>
 
 #include "nfp_net_ctrl.h"
@@ -1292,38 +1293,72 @@ static void nfp_net_rx_csum(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
        }
 }
 
-/**
- * nfp_net_set_hash() - Set SKB hash data
- * @netdev: adapter's net_device structure
- * @skb:   SKB to set the hash data on
- * @rxd:   RX descriptor
- *
- * The RSS hash and hash-type are pre-pended to the packet data.
- * Extract and decode it and set the skb fields.
- */
 static void nfp_net_set_hash(struct net_device *netdev, struct sk_buff *skb,
-                            struct nfp_net_rx_desc *rxd)
+                            unsigned int type, __be32 *hash)
 {
-       struct nfp_net_rx_hash *rx_hash;
-
-       if (!(rxd->rxd.flags & PCIE_DESC_RX_RSS) ||
-           !(netdev->features & NETIF_F_RXHASH))
+       if (!(netdev->features & NETIF_F_RXHASH))
                return;
 
-       rx_hash = (struct nfp_net_rx_hash *)(skb->data - sizeof(*rx_hash));
-
-       switch (be32_to_cpu(rx_hash->hash_type)) {
+       switch (type) {
        case NFP_NET_RSS_IPV4:
        case NFP_NET_RSS_IPV6:
        case NFP_NET_RSS_IPV6_EX:
-               skb_set_hash(skb, be32_to_cpu(rx_hash->hash), PKT_HASH_TYPE_L3);
+               skb_set_hash(skb, get_unaligned_be32(hash), PKT_HASH_TYPE_L3);
                break;
        default:
-               skb_set_hash(skb, be32_to_cpu(rx_hash->hash), PKT_HASH_TYPE_L4);
+               skb_set_hash(skb, get_unaligned_be32(hash), PKT_HASH_TYPE_L4);
                break;
        }
 }
 
+static void
+nfp_net_set_hash_desc(struct net_device *netdev, struct sk_buff *skb,
+                     struct nfp_net_rx_desc *rxd)
+{
+       struct nfp_net_rx_hash *rx_hash;
+
+       if (!(rxd->rxd.flags & PCIE_DESC_RX_RSS))
+               return;
+
+       rx_hash = (struct nfp_net_rx_hash *)(skb->data - sizeof(*rx_hash));
+
+       nfp_net_set_hash(netdev, skb, get_unaligned_be32(&rx_hash->hash_type),
+                        &rx_hash->hash);
+}
+
+static void *
+nfp_net_parse_meta(struct net_device *netdev, struct sk_buff *skb,
+                  int meta_len)
+{
+       u8 *data = skb->data - meta_len;
+       u32 meta_info;
+
+       meta_info = get_unaligned_be32(data);
+       data += 4;
+
+       while (meta_info) {
+               switch (meta_info & NFP_NET_META_FIELD_MASK) {
+               case NFP_NET_META_HASH:
+                       meta_info >>= NFP_NET_META_FIELD_SIZE;
+                       nfp_net_set_hash(netdev, skb,
+                                        meta_info & NFP_NET_META_FIELD_MASK,
+                                        (__be32 *)data);
+                       data += 4;
+                       break;
+               case NFP_NET_META_MARK:
+                       skb->mark = get_unaligned_be32(data);
+                       data += 4;
+                       break;
+               default:
+                       return NULL;
+               }
+
+               meta_info >>= NFP_NET_META_FIELD_SIZE;
+       }
+
+       return data;
+}
+
 /**
  * nfp_net_rx() - receive up to @budget packets on @rx_ring
  * @rx_ring:   RX ring to receive from
@@ -1438,14 +1473,29 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
                        skb_reserve(skb, nn->rx_offset);
                skb_put(skb, data_len - meta_len);
 
-               nfp_net_set_hash(nn->netdev, skb, rxd);
-
                /* Stats update */
                u64_stats_update_begin(&r_vec->rx_sync);
                r_vec->rx_pkts++;
                r_vec->rx_bytes += skb->len;
                u64_stats_update_end(&r_vec->rx_sync);
 
+               if (nn->fw_ver.major <= 3) {
+                       nfp_net_set_hash_desc(nn->netdev, skb, rxd);
+               } else if (meta_len) {
+                       void *end;
+
+                       end = nfp_net_parse_meta(nn->netdev, skb, meta_len);
+                       if (unlikely(end != skb->data)) {
+                               u64_stats_update_begin(&r_vec->rx_sync);
+                               r_vec->rx_drops++;
+                               u64_stats_update_end(&r_vec->rx_sync);
+
+                               dev_kfree_skb_any(skb);
+                               nn_warn_ratelimit(nn, "invalid RX packet metadata\n");
+                               continue;
+                       }
+               }
+
                skb_record_rx_queue(skb, rx_ring->idx);
                skb->protocol = eth_type_trans(skb, nn->netdev);
 
@@ -2386,6 +2436,31 @@ static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev,
        return stats;
 }
 
+static bool nfp_net_ebpf_capable(struct nfp_net *nn)
+{
+       if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
+           nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
+               return true;
+       return false;
+}
+
+static int
+nfp_net_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
+                struct tc_to_netdev *tc)
+{
+       struct nfp_net *nn = netdev_priv(netdev);
+
+       if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS))
+               return -ENOTSUPP;
+       if (proto != htons(ETH_P_ALL))
+               return -ENOTSUPP;
+
+       if (tc->type == TC_SETUP_CLSBPF && nfp_net_ebpf_capable(nn))
+               return nfp_net_bpf_offload(nn, handle, proto, tc->cls_bpf);
+
+       return -EINVAL;
+}
+
 static int nfp_net_set_features(struct net_device *netdev,
                                netdev_features_t features)
 {
@@ -2440,6 +2515,11 @@ static int nfp_net_set_features(struct net_device *netdev,
                        new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER;
        }
 
+       if (changed & NETIF_F_HW_TC && nn->ctrl & NFP_NET_CFG_CTRL_BPF) {
+               nn_err(nn, "Cannot disable HW TC offload while in use\n");
+               return -EBUSY;
+       }
+
        nn_dbg(nn, "Feature change 0x%llx -> 0x%llx (changed=0x%llx)\n",
               netdev->features, features, changed);
 
@@ -2589,6 +2669,7 @@ static const struct net_device_ops nfp_net_netdev_ops = {
        .ndo_stop               = nfp_net_netdev_close,
        .ndo_start_xmit         = nfp_net_tx,
        .ndo_get_stats64        = nfp_net_stat64,
+       .ndo_setup_tc           = nfp_net_setup_tc,
        .ndo_tx_timeout         = nfp_net_tx_timeout,
        .ndo_set_rx_mode        = nfp_net_set_rx_mode,
        .ndo_change_mtu         = nfp_net_change_mtu,
@@ -2614,7 +2695,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\n",
+       nn_info(nn, "CAP: %#x %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 " : "",
@@ -2631,7 +2712,8 @@ 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_VXLAN    ? "VXLAN "    : "",
-               nn->cap & NFP_NET_CFG_CTRL_NVGRE    ? "NVGRE "    : "");
+               nn->cap & NFP_NET_CFG_CTRL_NVGRE    ? "NVGRE "    : "",
+               nfp_net_ebpf_capable(nn)            ? "BPF "      : "");
 }
 
 /**
@@ -2674,10 +2756,13 @@ struct nfp_net *nfp_net_netdev_alloc(struct pci_dev *pdev,
        nn->rxd_cnt = NFP_NET_RX_DESCS_DEFAULT;
 
        spin_lock_init(&nn->reconfig_lock);
+       spin_lock_init(&nn->rx_filter_lock);
        spin_lock_init(&nn->link_status_lock);
 
        setup_timer(&nn->reconfig_timer,
                    nfp_net_reconfig_timer, (unsigned long)nn);
+       setup_timer(&nn->rx_filter_stats_timer,
+                   nfp_net_filter_stats_timer, (unsigned long)nn);
 
        return nn;
 }
@@ -2799,6 +2884,9 @@ int nfp_net_netdev_init(struct net_device *netdev)
 
        netdev->features = netdev->hw_features;
 
+       if (nfp_net_ebpf_capable(nn))
+               netdev->hw_features |= NETIF_F_HW_TC;
+
        /* Advertise but disable TSO by default. */
        netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);