be2net: Export tunnel offloads only when a VxLAN tunnel is created
[cascardo/linux.git] / drivers / net / ethernet / emulex / benet / be_main.c
index 3e8475c..2aacd47 100644 (file)
@@ -887,7 +887,8 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
        }
 
        if (vlan_tag) {
-               skb = __vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
+               skb = vlan_insert_tag_set_proto(skb, htons(ETH_P_8021Q),
+                                               vlan_tag);
                if (unlikely(!skb))
                        return skb;
                skb->vlan_tci = 0;
@@ -896,7 +897,8 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
        /* Insert the outer VLAN, if any */
        if (adapter->qnq_vid) {
                vlan_tag = adapter->qnq_vid;
-               skb = __vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
+               skb = vlan_insert_tag_set_proto(skb, htons(ETH_P_8021Q),
+                                               vlan_tag);
                if (unlikely(!skb))
                        return skb;
                if (skip_hw_vlan)
@@ -1015,9 +1017,8 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
         * to pad short packets (<= 32 bytes) to a 36-byte length.
         */
        if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
-               if (skb_padto(skb, 36))
+               if (skb_put_padto(skb, 36))
                        return NULL;
-               skb->len = 36;
        }
 
        if (BEx_chip(adapter) || lancer_chip(adapter)) {
@@ -2853,10 +2854,10 @@ static int be_close(struct net_device *netdev)
 
 static int be_rx_qs_create(struct be_adapter *adapter)
 {
+       struct rss_info *rss = &adapter->rss_info;
+       u8 rss_key[RSS_HASH_KEY_LEN];
        struct be_rx_obj *rxo;
        int rc, i, j;
-       u8 rss_hkey[RSS_HASH_KEY_LEN];
-       struct rss_info *rss = &adapter->rss_info;
 
        for_all_rx_queues(adapter, rxo, i) {
                rc = be_queue_alloc(adapter, &rxo->q, RX_Q_LEN,
@@ -2901,15 +2902,15 @@ static int be_rx_qs_create(struct be_adapter *adapter)
                rss->rss_flags = RSS_ENABLE_NONE;
        }
 
-       get_random_bytes(rss_hkey, RSS_HASH_KEY_LEN);
+       netdev_rss_key_fill(rss_key, RSS_HASH_KEY_LEN);
        rc = be_cmd_rss_config(adapter, rss->rsstable, rss->rss_flags,
-                              128, rss_hkey);
+                              128, rss_key);
        if (rc) {
                rss->rss_flags = RSS_ENABLE_NONE;
                return rc;
        }
 
-       memcpy(rss->rss_hkey, rss_hkey, RSS_HASH_KEY_LEN);
+       memcpy(rss->rss_hkey, rss_key, RSS_HASH_KEY_LEN);
 
        /* First time posting */
        for_all_rx_queues(adapter, rxo, i)
@@ -3123,6 +3124,8 @@ static void be_mac_clear(struct be_adapter *adapter)
 #ifdef CONFIG_BE2NET_VXLAN
 static void be_disable_vxlan_offloads(struct be_adapter *adapter)
 {
+       struct net_device *netdev = adapter->netdev;
+
        if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS)
                be_cmd_manage_iface(adapter, adapter->if_handle,
                                    OP_CONVERT_TUNNEL_TO_NORMAL);
@@ -3132,6 +3135,9 @@ static void be_disable_vxlan_offloads(struct be_adapter *adapter)
 
        adapter->flags &= ~BE_FLAGS_VXLAN_OFFLOADS;
        adapter->vxlan_port = 0;
+
+       netdev->hw_enc_features = 0;
+       netdev->hw_features &= ~(NETIF_F_GSO_UDP_TUNNEL);
 }
 #endif
 
@@ -4309,11 +4315,16 @@ static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh)
                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;
+
                mode = nla_get_u16(attr);
                if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB)
                        return -EINVAL;
@@ -4360,10 +4371,24 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
 
        return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
                                       hsw_mode == PORT_FWD_TYPE_VEPA ?
-                                      BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB);
+                                      BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB,
+                                      0, 0);
 }
 
 #ifdef CONFIG_BE2NET_VXLAN
+/* VxLAN offload Notes:
+ *
+ * The stack defines tunnel offload flags (hw_enc_features) for IP and doesn't
+ * distinguish various types of transports (VxLAN, GRE, NVGRE ..). So, offload
+ * is expected to work across all types of IP tunnels once exported. Skyhawk
+ * supports offloads for either VxLAN or NVGRE, exclusively. So we export VxLAN
+ * offloads in hw_enc_features only when a VxLAN port is added. Note this only
+ * ensures that other tunnels work fine while VxLAN offloads are not enabled.
+ *
+ * Skyhawk supports VxLAN offloads only for one UDP dport. So, if the stack
+ * adds more than one port, disable offloads and don't re-enable them again
+ * until after all the tunnels are removed.
+ */
 static void be_add_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
                              __be16 port)
 {
@@ -4375,13 +4400,16 @@ static void be_add_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
                return;
 
        if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) {
-               dev_warn(dev, "Cannot add UDP port %d for VxLAN offloads\n",
-                        be16_to_cpu(port));
                dev_info(dev,
                         "Only one UDP port supported for VxLAN offloads\n");
-               return;
+               dev_info(dev, "Disabling VxLAN offloads\n");
+               adapter->vxlan_port_count++;
+               goto err;
        }
 
+       if (adapter->vxlan_port_count++ >= 1)
+               return;
+
        status = be_cmd_manage_iface(adapter, adapter->if_handle,
                                     OP_CONVERT_NORMAL_TO_TUNNEL);
        if (status) {
@@ -4397,6 +4425,11 @@ static void be_add_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
        adapter->flags |= BE_FLAGS_VXLAN_OFFLOADS;
        adapter->vxlan_port = port;
 
+       netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+                                  NETIF_F_TSO | NETIF_F_TSO6 |
+                                  NETIF_F_GSO_UDP_TUNNEL;
+       netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
+
        dev_info(dev, "Enabled VxLAN offloads for UDP port %d\n",
                 be16_to_cpu(port));
        return;
@@ -4413,13 +4446,15 @@ static void be_del_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
                return;
 
        if (adapter->vxlan_port != port)
-               return;
+               goto done;
 
        be_disable_vxlan_offloads(adapter);
 
        dev_info(&adapter->pdev->dev,
                 "Disabled VxLAN offloads for UDP port %d\n",
                 be16_to_cpu(port));
+done:
+       adapter->vxlan_port_count--;
 }
 
 static bool be_gso_check(struct sk_buff *skb, struct net_device *dev)
@@ -4463,12 +4498,6 @@ static void be_netdev_init(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
-       if (skyhawk_chip(adapter)) {
-               netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                                          NETIF_F_TSO | NETIF_F_TSO6 |
-                                          NETIF_F_GSO_UDP_TUNNEL;
-               netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
-       }
        netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
                NETIF_F_HW_VLAN_CTAG_TX;